4

Python and PowerShell use # to denote to the parser that everything after them until the line break is a comment. They even provide block comments for multiline situations. However, there is no counterpart to the aforementioned that provides its opposite - the ability to denote that everything before the symbol is a comment.

Consequently, is there a reason why consensus is so unanimous that comments are to be appended, rather than prepended, to the extent that the ability to facilitate this style is generally not even provided in most languages (especially those without inline comments, like the aforementioned Python)?

See the undermentioned for comparative examples:

  1. Reversed

    Print hello # print("Hello") Print world # print("World") Import math # import math Define circle # def circle_area(radius): Calculate area # return math.pi * radius ** 2 Print area # print(circle_area(5)) Define factorial # def factorial(n): Base case # if n == 0: Return 1 # return 1 Recursive case # else: Return n * fac # return n * factorial(n - 1) Print factorial # print(factorial(5)) 
  2. Standard

    print("Hello") # Print hello print("World") # Print world import math # Import math def circle_area(radius): # Define circle return math.pi * radius ** 2 # Calculate area print(circle_area(5)) # Print area def factorial(n): # Define factorial if n == 0: # Base case return 1 # Return 1 else: # Recursive case return n * factorial(n - 1) # Return n * fac print(factorial(5)) # Print factorial 
Hypotheses
  1. I initially presumed it might be because of comment alignment, but evaluated this, and noticed that it functioned approximately as well as comments on languages with limited line length do currently.

  2. My last and best estimate is the dominance of LTR script amongst programming languages (despite its use of Arabic numerals).

Discovery

If of interest, I noticed this absence when answering stackoverflow.com/revisions/79048760/10 – I wanted a way to include the ability to create dotfiles whilst maintaining PowerShell syntax compatibility. I was, of course, unsuccessful in this due to the absence of this.

I'd not previously contemplated its absence, which is perhaps an answer to this question in and of itself. However, it's unsatisfactory - I find it improbable (and somewhat egotistical) to expect that I'm the first to evaluate the (un)usefulness of such functionality.

7
  • 3
    The implication of this scheme seems to be that each line starts in comment mode, and there is then a comment terminator after which code begins. What's not clear is whether every code line must be prefixed by a comment terminator, or how a line without any comment terminator would be treated (as entirely comment, entirely code, or invalid?). In any event, the parsing is liable to be less efficient for the mainstream case. (1/2) Commented Oct 4, 2024 at 6:51
  • 1
    Comments usually make up fewer lines than code, and the left-columnar comment layout shown in the question can already be produced by using inline comments with opening and closing tokens (a syntax concept that is already more general and fits many purposes). So it appears to be a very specialist device that doesn't justify its own cost. (2/2). Commented Oct 4, 2024 at 6:51
  • 1
    In either scheme, those comments range from pointless ("Print factorial") to actively misleading ("Define circle") Commented Oct 4, 2024 at 9:08
  • 3
    Technical reasons aside, it would read awkwardly. It would not be obvious what you are reading (code or comment), it would remain a surprise until your eyes hit the marker. No one would appreciate that. Commented Oct 4, 2024 at 12:04
  • 1
    @RokeJulianLockhart A point of ambiguity in your description: If there is no comment marker on a line, does this mean the whole line is code or the whole line is a comment? This makes a big difference! Some answers assume the first and some answers assume the second case. Commented Apr 10 at 16:34

5 Answers 5

8

I'm going to say because of parsing.

To do it the way you ask, you'd have to keep and parse all the text (including syntax errors) until you've established it's not a comment to be thrown away, then go back and compile/interpret it.

The traditional way is much, much easier: "Ignore everything until you get EOL or close comment". This is easier to do efficiently in a single pass, especially for an interpreter.

5
  • 2
    While I agree I think it is at the lexer level and it is not ambiguity but the fact comments do not need escaping. So they are "safe". With code-comment reversed now you would have to escape both code (as usual) and comments too, because you could have character # denoting regular character in the comment. Commented Oct 4, 2024 at 5:53
  • 4
    I am sure this is about parsing, but not as this answer pretends. It is about parsing by the human reader, who has to sort out comments from code very much the same way as it is described here. Commented Oct 4, 2024 at 6:14
  • 4
    Computers, being what they are, are perfectly able to parse backwards and eliminate this concern. Humans are as well. Entire languages are written right to left. No it's combining a left to right language with right to left parsing that makes this weird. This problem has a name. It's called little endian. Commented Oct 4, 2024 at 10:38
  • 1
    A parser would have no trouble with this: it would simply discard input at the beginning of each line until it reached the end-of-comment/start-of-code character. Commented Oct 4, 2024 at 15:37
  • 2
    This has nothing to do with parsers. If writing such way would be easier, we would write such parsers. That's not an issue at all. This of course is due to the fact that most programming languages are directly related to English language, where we read/write left to right. Commented Oct 4, 2024 at 17:18
5

The example you provided is problematic, since it is a perfect illustration of how not to use comments in the first place. They are perfectly useless, and barely repeat the source code. Besides, you commented every single line, which makes no sense. Never do that.

Let's imagine, now, a more realistic example. Or rather two examples, one from .NET Framework, one from Python.

Example from .NET Framework

Here's a random file. At line 447, you find the that the try block is followed by this:

 } catch (ArgumentException) { } catch (NotSupportedException) { } // Security can throw this on ":" catch (SecurityException) { } 

At line 1359, you have this:

 int dataInitialised = 0; if (tryagain) // someone has a handle to the file open, or other error { 

Example from Python

Take Python's requests library. In one of the files, most comments are on their own lines, but two are at the end of a line.

Line 9:

import os.path import socket # noqa: F401 import typing import warnings 

Line 569:

 url = request.path_url if url.startswith("//"): # Don't confuse urllib3 url = f"/{url.lstrip('/')}" 

The first one is not strictly a comment, but a statement for the linter, but one may imagine a similar comment such as:

import os.path import socket # Necessary to do this or that. import typing import warnings 

Analysis

Those are indeed four relevant examples. All comments are short (if they were long, they would go on separate lines), and they all add something to the line.

Now how exactly would you do it if comments were coming first? Maybe like this?

 } catch (ArgumentException) { } Security can throw this on ":" // catch (NotSupportedException) { } catch (SecurityException) { } [...] int dataInitialised = 0; someone has a handle to the file open, or other error // if (tryagain) { 

and:

import os.path Necessary to do this or that. # import socket import typing import warnings [...] def request_url(self, request, proxies): url = request.path_url Don't confuse urllib3 # if url.startswith("//"): url = f"/{url.lstrip('/')}" 

It makes the code hard to read. Naturally, with syntax highlighting, it could be easier to spot the catch, the conditions, or the import, but still, it is much less natural to read. Possible alternative:

 } catch (ArgumentException) { } Security can throw this on ":" // catch (NotSupportedException) { } catch (SecurityException) { } [...] int dataInitialised = 0; someone has a handle to the file open, or other error // if (tryagain) { 
 import os.path Necessary to do this or that. # import socket import typing import warnings [...] def request_url(self, request, proxies): url = request.path_url Don't confuse urllib3 # if url.startswith("//"): url = f"/{url.lstrip('/')}" 

Now the code is shown all together, but the indentation has to be changed every time someone changes the comment. Imagine replacing “this or that” by “something,” and now you need to move all the import statements three spaces to the left. Also, blocks of code find themselves too bit to the right, making it necessary to use horizontal scroll.

So no, left-positioned comments work for your example because your example is flawed in the first place. For real-world comments, it doesn't work.

Additional reason

Another reason for the comments to be appended rather than prepended is that comments have to add something to the code. And it makes sense, therefore, to position them at the end. Imagine it this way: you read a sentence, and if you don't understand it, a friend may explain it to you. It wouldn't make sense for your friend to start explaining it before you read the actual sentence—maybe you don't even need an explanation after all.

In the very first example with a list of catch statements, as you read it from left to right, it makes sense. You're reading the list of exceptions that make sense, and then you encounter NotSupportedException. “What the heck a NotSupportedException doing here?”—you ask yourself, and immediately get the answer. The three other examples are similar. I think you get the point.

3

For "why is this feature not supported"-questions, a possible answer is often that nobody thought about it. For Python in particular, it is a fundamental design principle that the visual indentation should match the logical structure of the code. Since prefixed comments would destroy this property, it is likely nobody in the Python community ever even imagined such a thing. If proposed, they certainly would reject the idea out of hand.

But many other languages have block-comments which can also be placed inline, including at the start of the line. For example /* .. */ comments in C-derived languages or <# .. #> in Powershell.

But your specific proposal suggest comments with no distinct start-marker, only an end-marker. This present some difficulties for a parser. A parser scans characters into "tokens" (numbers, strings, comments, identifiers, operators etc.) by scanning the file from beginning to end. A token is recognized by one or more leading characters which unambiguously identifies the token, eg. " for a string, a digit for a number, # for a comment etc. But in your proposal, the scanner would have to parse an unknown number of characters before potentially reaching the marker-character which indicate that the previous text from the beginning of the line is a comment. This would require the scanner to backtrack and re-scan the line with the new information, which would be slow and complex. It would also introduce some ambiguities.

For example imagine a line:

"Hello # print("hello") 

A scanner would start parsing a string. Given # is a valid character inside a normal string, it would parse until the second quote and probably signal a confusing syntax error after that.

Likely this could only be solved by a separate pre-scanner pass which identifies prefixed comments before the regular scanner pass. But given parsers are already quite complex, I doubt anybody would want to add that.

The closest to your suggestion I have seen is Haskell's literate-mode, where every line is parsed as a comment by default, while code has to be prefixed with a >. But the code marker has to be the first character on the line, so there is no ambiguity or need for backtracking.

7
  • 1
    Note that literate mode is not original to Haskell, but borrowed Knuth's (original?) idea of literate programming implemented in WEB (his fusion of TeX and Pascal used to write the original TeX compiler). Commented Oct 4, 2024 at 15:33
  • Note too that f-string fields can contain comments as of Python 3.12, so the example you give is no longer an argument against (though it is, in some sense, an argument as to why support for such "internal" comments was delayed as long as it was). Commented Oct 4, 2024 at 15:44
  • Is this partially due to lines being terminated rather than begun? As in, we use EOL markers, rather than start-of-line (SOL) markers...? I realize that the distinction is a little arbitrary, but in this case, perhaps it matters? Commented Oct 4, 2024 at 18:15
  • 1
    @RokeJulianLockhart That predates Python 3.12, which was release in late 2023. Commented Oct 4, 2024 at 18:19
  • 1
    @RokeJulianLockhart No, but it is relate to parsers scanning from the beginning of the line to the end of the line rather than opposite direction. Commented Oct 4, 2024 at 18:28
2

This is essentially a style of literate programming, where instead of embedding comments in what is primarily source code, you embed code in what is primarily comments.

Most languages, however, emphasize code over comments.

2
  • For example, Knuth's CWEB Commented Oct 4, 2024 at 21:03
  • Today, you're more likely to use a tool that grabs code blocks out of a Markdown document. I've implemented that myself a couple times. Commented Oct 4, 2024 at 21:04
1

C and c++ do. Mark a line as “comment until marker mode” by starting it with /*, then use */ as a marker turning everything from the start of the line to this marker into a comment.

It is even more flexible: If you want some letters at the start of the line to be code, not comment, then put the “comment until marker mode” /* at the first position you want to be a comment.

Downvoter is welcome to point out any errors.

3
  • I'm not the downvoter you refer to. However, I'm aware that inline comments exists - I've used them in the aforereferenced PowerShell scripting language. They're denoted by <# and #> (if you're unfamiliar with the language). They obviously function very differently to # or //. Commented Oct 4, 2024 at 18:18
  • 1
    They do exactly what you asked for. Not what you were looking for, but what you asked for. Commented Oct 4, 2024 at 19:49
  • I've not requested an exaplanation of how to perform a function - merely examples of a specific implementation of functionality, and relevant rationale. Thanks, though. Commented Oct 4, 2024 at 22:07

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.