• Long Docstrings

    From Lawrence D'Oliveiro@21:1/5 to All on Thu Jan 18 07:52:34 2024
    I often write long docstrings (not sure whether Lisp has its own name
    for these). In Python, if the body of a class or function begins with
    a string literal, then this becomes the docstring. And a REPL will
    display this as help text if you type “help(«object»)”. E.g.

    class Matrix :
    "representation of a 3-by-2 affine homogeneous matrix. This does not" \
    " actually use any Cairo routines to implement its calculations; these" \
    " are done entirely using Python numerics. The from_cairo and to_cairo" \
    " methods provide conversion to/from cairo_matrix_t structs. Routines" \
    " elsewhere expect this Matrix type where the underlying Cairo routine" \
    " wants a cairo_matrix_t, and return this type where the Cairo routine" \
    " returns a cairo_matrix_t."

    ...

    #end Matrix

    This takes advantage of the fact that, like C and some C-derivatives,
    Python supports implicit concatenation of adjacent string literals.
    This allows me to construct very long string literals without messing
    up the layout of my code.

    Lisp doesn’t have such an implicit-concatenation convention. But it
    has macros. And it easy enough to define a macro which does string concatenation at macro-invocation time, e.g.

    (defmacro mstr (&rest strs)
    "lets me define a long string literal in pieces across lines, useful for docstrings."
    (apply 'concat strs)
    ) ; defmacro mstr

    And using this macro is equally easy:

    (defun cur-line (ensure-newline)
    (mstr
    "returns list of two character positions, representing the"
    " beginning and end of the selection if there is one, else"
    " the beginning and end of the current line. ensure-newline"
    " => ensures there is a newline at the end of the line."
    )
    ...
    ) ; defun

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Madhu@21:1/5 to All on Thu Jan 18 15:14:27 2024
    * Lawrence D'Oliveiro <uoalc1$2gjnk$1 @dont-email.me> :
    Wrote on Thu, 18 Jan 2024 07:52:34 -0000 (UTC):

    I often write long docstrings (not sure whether Lisp has its own name
    for these). In Python, if the body of a class or function begins with
    a string literal, then this becomes the docstring. And a REPL will
    display this as help text if you type “help(«object»)”. E.g.

    class Matrix :
    "representation of a 3-by-2 affine homogeneous matrix. This does not" \
    " actually use any Cairo routines to implement its calculations; these" \
    " are done entirely using Python numerics. The from_cairo and to_cairo" \
    " methods provide conversion to/from cairo_matrix_t structs. Routines" \
    " elsewhere expect this Matrix type where the underlying Cairo routine" \
    " wants a cairo_matrix_t, and return this type where the Cairo routine" \
    " returns a cairo_matrix_t."

    ...

    #end Matrix

    This takes advantage of the fact that, like C and some C-derivatives,
    Python supports implicit concatenation of adjacent string literals.
    This allows me to construct very long string literals without messing
    up the layout of my code.

    Why do you want to split strings?

    in python can't you just put the documentation in a string with embedded newlines?
    the length of each line will be under screenwidth.

    """ representation of a 3-by-2 affine homogeneous matrix. This does not actually use any Cairo routines to implement its calculations;
    these[...] """

    Lisp doesn’t have such an implicit-concatenation convention. But it
    has macros. And it easy enough to define a macro which does string concatenation at macro-invocation time, e.g.

    lisp strings (the ~ quoting convention) embed newlines by default.


    (defmacro mstr (&rest strs)
    "lets me define a long string literal in pieces across lines, useful for docstrings."
    (apply 'concat strs)
    ) ; defmacro mstr

    And using this macro is equally easy:

    (defun cur-line (ensure-newline)
    (mstr
    "returns list of two character positions, representing the"
    " beginning and end of the selection if there is one, else"
    " the beginning and end of the current line. ensure-newline"
    " => ensures there is a newline at the end of the line."
    )
    ...
    ) ; defun

    You could just have said

    (defun cur-line (ensure-newline)
    "returns list of two character positions, representing the
    beginning and end of the selection if there is one, else
    the beginning and end of the current line. ensure-newline
    ensures there is a newline at the end of the line."
    )

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Madhu on Thu Jan 18 20:49:20 2024
    On Thu, 18 Jan 2024 15:14:27 +0530, Madhu wrote:

    in python can't you just put the documentation in a string with embedded newlines?

    You mean triple-quoted strings? And having to add extra blanks at the
    start of each line, throwing the formatting off?

    You could just have said

    Which is why I said “without messing up the layout of my code.”

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Lawrence D'Oliveiro on Thu Jan 18 22:39:37 2024
    On 2024-01-18, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
    I often write long docstrings (not sure whether Lisp has its own name
    for these).

    Lis has its own name: docstrings. It is Python that doesn't have its own name.

    (defmacro mstr (&rest strs)
    "lets me define a long string literal in pieces across lines, useful for docstrings."
    (apply 'concat strs)

    What is concat?

    ) ; defmacro mstr

    Another solution would be to make the macro take a format argument.
    Common Lisp has a mechanism inside format strings for removing a newline
    and eating the whitespace which follows: tilde before a newline.

    (format nil "this is a ~
    multi-line ~
    print job that ~
    becomes one line.")

    But ...

    And using this macro is equally easy:

    (defun cur-line (ensure-newline)
    (mstr
    "returns list of two character positions, representing the"
    " beginning and end of the selection if there is one, else"
    " the beginning and end of the current line. ensure-newline"
    " => ensures there is a newline at the end of the line."
    )

    I am concerned whether this is actually valid syntax for specifying
    a docstring.

    Note that according to ANSI CL, the syntax of defun is:

    defun function-name lambda-list [[declaration* | documentation]] form*

    You see how "declaration" and "form" are distinct? Further, the
    specification says:

    documentation---a string; not evaluated.

    It's not evaluated, because it's not a form. The documentation
    must be a string literal element in the defun syntax.

    Your (mstr ...) therefore doesn't correspond to the "documentation"
    element, it is a form.

    Nowhere does the spec say that the forms enclosed in defun are
    macroexpanded in order to look for docstrings.

    It's indeed not working for me in CLISP.

    If I define this:

    (defun fn () "abc" 42)

    the function has "abc" documentation. If I use this:

    (defun fn () (mstr "abc") 42)

    then it has NIL documentation.

    (defmacro mstr () "abc")
    MSTR
    (mstr)
    "abc"
    (defun fn () (mstr) 42)
    FN
    (documentation 'fn 'function)
    NIL
    (defun fn () "abc" 42)
    FN
    (documentation 'fn 'function)
    "abc"

    You need to make your own defun-doc macro to make this work, or else
    (yuck) rely on read-time #. evaluation.

    ;; using your concat

    (defmacro defun-doc (name args docstring-list &body body)
    `(defun ,name ,args ,(apply #'concat docstring-list) ,@body))

    This macro sidesteps the problem by generating a defun which
    a string object in the docstring position. defun nevers sees
    anything but a string object there.

    I would make the macro smart so that it checks for the missing
    docstring-list, without which the first argument of the body will
    be taken for that position. Like checking that docstring-list is
    a proper list, all of whose elements are strings.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David De La Harpe Golden@21:1/5 to Kaz Kylheku on Fri Jan 19 01:10:54 2024
    On 18/01/2024 22:39, Kaz Kylheku wrote:
    On 2024-01-18, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
    I often write long docstrings (not sure whether Lisp has its own name
    for these).

    Lis has its own name: docstrings. It is Python that doesn't have its own name.


    They're certainly normally called docstrings or documentation strings in python. I expect python got the idea from lisp in the first place.

    peps.python.org/pep-0257/#what-is-a-docstring peps.python.org/pep-0008/#documentation-strings

    Normal (and stated in the relevant PEPs!) python convention IS to use
    python's triple-double-quoted """multiline-string""" literals for them uniformly, though.

    It's not idiomatic to use python's single-line-restricted
    "double-quoted string" literals for them. Not made syntactically
    illegal, but odd.

    Common python documentation processors using python docstrings as input
    do just expect the bit of excess whitespace that ends up embedded in the docstrings, and generally just trim it away. There's, like, functions in
    the stdlib for it

    docs.python.org/3/library/inspect.html#inspect.cleandoc

    It's also very common to write python docstrings in
    Sphinx/reStructuredText syntax specifically (has the advantage of still remaining fairly readable when viewed as plaintext) on the assumption
    they'll also be pulled into the project's generated Sphinx documentation.

    www.sphinx-doc.org/en/master/usage/quickstart.html#autodoc

    Anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Madhu@21:1/5 to All on Fri Jan 19 06:53:32 2024
    * Lawrence D'Oliveiro <uoc2sg$2oa3u$3 @dont-email.me> :
    Wrote on Thu, 18 Jan 2024 20:49:20 -0000 (UTC):
    On Thu, 18 Jan 2024 15:14:27 +0530, Madhu wrote:
    in python can't you just put the documentation in a string with embedded
    newlines?
    You mean triple-quoted strings? And having to add extra blanks at the
    start of each line, throwing the formatting off?
    You could just have said
    Which is why I said “without messing up the layout of my code.”

    Sorry I misunderstood, I thought you wanted (documentation function) to
    yield formatted text and not a single line.

    What Kaz said applies for emacs lisp too (`concat' gives it away) -- the docstring has to be a string.

    try add a declaration "(declare (speed 0))" for elisp
    or "(declare (optimize (speed 0)))" after the docstring to see the
    problem.

    elisp will both complain
    - Warning: docstring wider than 80
    - diagnose a Warning: Stray ‘declare’ form: (declare (speed 0))

    common lisp should blow up on compilation.
    ```
    While compiling CUR-LINE :
    The DECLARE expression (DECLARE
    (OPTIMIZE
    (SPEED 0))) is being treated as a form,
    possibly because it's the result of macroexpansion. DECLARE expressions
    can only appear in specified contexts and must be actual subexpressions
    of the containing forms.
    ```

    But you can get around it by using #.(mstr .... ) for the docstring
    and evaluate it at read time.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to David De La Harpe Golden on Fri Jan 19 22:26:38 2024
    On Fri, 19 Jan 2024 01:10:54 +0000, David De La Harpe Golden wrote:

    It's not idiomatic to use python's single-line-restricted "double-quoted string" literals for them. Not made syntactically illegal, but odd.

    I have no idea why people design a language one way, then expect you to
    use it a different way.

    Common python documentation processors using python docstrings as input
    do just expect the bit of excess whitespace that ends up embedded in the docstrings, and generally just trim it away. There's, like, functions in
    the stdlib for it

    I wonder why you need to use them ...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lawrence D'Oliveiro@21:1/5 to Madhu on Fri Jan 19 22:23:11 2024
    On Fri, 19 Jan 2024 06:53:32 +0530, Madhu wrote:

    elisp will both complain ...

    I have used this successfully in elisp.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Lawrence D'Oliveiro on Sat Jan 20 00:32:09 2024
    On 2024-01-19, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
    On Fri, 19 Jan 2024 01:10:54 +0000, David De La Harpe Golden wrote:

    It's not idiomatic to use python's single-line-restricted "double-quoted
    string" literals for them. Not made syntactically illegal, but odd.

    I have no idea why people design a language one way, then expect you to
    use it a different way.

    Common python documentation processors using python docstrings as input
    do just expect the bit of excess whitespace that ends up embedded in the
    docstrings, and generally just trim it away. There's, like, functions in
    the stdlib for it

    I wonder why you need to use them ...

    And why doesn't the Python compiler use them to sanitize the docstring
    when the function definition is processed, to spare the tooling from
    having to do it.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David De La Harpe Golden@21:1/5 to Kaz Kylheku on Sat Jan 20 13:38:32 2024
    On 20/01/2024 00:32, Kaz Kylheku wrote:

    I wonder why you need to use them ...

    And why doesn't the Python compiler use them to sanitize the docstring
    when the function definition is processed, to spare the tooling from
    having to do it.



    Well, sounds like they may well be about to do something like that for
    Python 3.13 shortly (at least for compiled files) - pre-release notes -

    docs.python.org/3.13/whatsnew/3.13.html

    Compiler now strip indents from docstrings. This will reduce the size
    of bytecode cache (e.g. .pyc file). For example, cache file size for sqlalchemy.orm.session in SQLAlchemy 2.0 is reduced by about 5%. This
    change will affect tools using docstrings, like doctest.

    Not sure about backward compat though, seems like it would necessarily
    be quite a breaking change (seeing as docstrings have in fact preserved line-leading whitespace all along, if only to be later typically but not necessarily stripped)

    Was debate ongoing 2 weeks ago whether they roll back on the change or not:

    github.com/python/cpython/issues/81283#issuecomment-1878628233


    Shrug. Not my circus not my monkeys etc.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to David De La Harpe Golden on Sun Jan 21 05:01:32 2024
    On 2024-01-20, David De La Harpe Golden <david@harpegolden.net> wrote:
    On 20/01/2024 00:32, Kaz Kylheku wrote:

    I wonder why you need to use them ...

    And why doesn't the Python compiler use them to sanitize the docstring
    when the function definition is processed, to spare the tooling from
    having to do it.

    Well, sounds like they may well be about to do something like that for
    Python 3.13 shortly (at least for compiled files) - pre-release notes -

    docs.python.org/3.13/whatsnew/3.13.html

    Compiler now strip indents from docstrings. This will reduce the size
    of bytecode cache (e.g. .pyc file). For example, cache file size for sqlalchemy.orm.session in SQLAlchemy 2.0 is reduced by about 5%. This
    change will affect tools using docstrings, like doctest.

    Under my watch, this obvious thing would have been done 20 years ago.

    (Well, if I didn't hate docstrings.)

    The Python people are slow on the uptake.

    Not sure about backward compat though, seems like it would necessarily
    be quite a breaking change (seeing as docstrings have in fact preserved line-leading whitespace all along, if only to be later typically but not necessarily stripped)

    Was debate ongoing 2 weeks ago whether they roll back on the change or not:

    github.com/python/cpython/issues/81283#issuecomment-1878628233

    Undoubtedly, some of these nincompoops have managed to stow away
    textual Python source inside docstrings, whose semantics is destroyed
    by the stripping.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)