Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Style guide discussion: naming convention for entry points #875

Closed
cgranade opened this issue Jun 2, 2020 · 12 comments · Fixed by #937
Closed

Style guide discussion: naming convention for entry points #875

cgranade opened this issue Jun 2, 2020 · 12 comments · Fixed by #937

Comments

@cgranade
Copy link
Contributor

cgranade commented Jun 2, 2020

With the introduction of Q# standalone executables, we now have an @EntryPoint() attribute that can be used to denote that an operation should be the entry point into a Q# application when called at the command line, and that the operation is available for interoperability with .NET and Python. In conventional classical languages, entry points are often called some form of "main" (e.g.: main, Main, or __main__) to expose them and to denote that they are entry points. As per that convention, @anpaz-msft has raised the point that Q# operations marked as @EntryPoint() should be named Main() by convention, even if that would otherwise not be consistent with the style guide. This issue is intended to kick off that discussion and to make sure that wherever we wind up landing on this case, that the style guide gives explicit and actionable guidance about how to name entry points.

In that spirit, I've written out my own thoughts; I tend towards naming entry points as ordinary operations, so my list of thoughts is necessarily a bit biased as result, but I can definitely see the argument of naming entry points as Main() as well.

  • Pros of naming entry points as Main():
    • Keeps to convention set in classical languages like C, C#, and Python.
    • Clearly understandable, even if @EntryPoint() is not familiar.
    • Entry points generally only called from interop, not from within Q#; name within Q# is thus less informative when writing Q# code.
  • Pros of naming entry points as ordinary operations:
    • Less edge cases to style guide.
    • Names exposed to interop are meaningful.
    • Reduces redundancy between @EntryPoint() and operation name.
    • Keeps to convention set by GPGPU languages, where entry points represent kernels.
    • Generalizes if multiple entry points are ever allowed.
@geduardo
Copy link
Contributor

geduardo commented Jun 2, 2020

Interesting discussion. I don't have more pros for any of the options, but I do think that when accessibility and consistency with the style guide are confronted we should seek accessibility. Even at the expense of less consistent style rules. In general, many users don't follow strictly the style guides. We want to make the language as accessible as possible to get broader audiences. Familiarity with other languages is always a very strong feature for accessibility.

So I'll go for Main(), but don't take my opinion very seriously since I'm just a noob in computer science and programming languages!

@anpaz
Copy link
Collaborator

anpaz commented Jun 2, 2020

As you pointed out, I'm of the opinion we should use Main.
In particular, I suspect the EntryPoint should have the logic to run the program, and when you want to use a Q# operation from another Q# program you don't really want to call the entry point but its useful operations as the new program will have its own main logic.
You covered very well pros of each approach, though, and as long as it's part of the style guide I don't have a strong opinion.

@anpaz
Copy link
Collaborator

anpaz commented Jun 2, 2020

And, like in C#, it should be more of a convention than a rule enforced by the compiler.

@geduardo
Copy link
Contributor

geduardo commented Jun 9, 2020

So what do we decide? Shall we modify the documentation and the style guide?

@cgranade
Copy link
Contributor Author

cgranade commented Jun 9, 2020

@geduardo: Thanks for the ping, easy for these kinds of discussions to get lost. I definitely appreciate your and @anpaz-msft's perspectives, but I'd also like to get a little bit more input before resolving if possible.

@geduardo
Copy link
Contributor

I agree @cgranade, this is an important discussion. More people should be involved. Tagging some people to raise awareness:
@gillenhaalb @KittyYeungQ @Bradben @tcNickolas @bettinaheim @rmshaffer @samarsha

@bamarsha
Copy link
Contributor

bamarsha commented Jun 10, 2020

I would prefer to use descriptive operation names instead of Main.

I think that other languages originally used Main because they didn't have another way to tag a function as being the entry point; the name was hard-coded. In Q#, the name doesn't matter, and while following conventions from other languages can make Q# easier to learn, I don't think this is one of those cases. I think that using Main when it is unnecessary can actually create confusion, because users coming from languages where Main is required may see it in Q# and think that it is also required, when actually the @EntryPoint() attribute is doing all of the work.

Even in languages where the name Main is not required, you could still argue that you should call it Main because it is the only function that has to directly handle parsing the command-line argument string, before handing off the arguments to a normal function. But that isn't true in Q#, either. Q# entry points are strongly typed, and their parameters are the same as any other operation.

IMO, a good Q# entry point should be indistinguishable from other operations, and the name should reflect that. I don't know if Q# should support multiple entry points, but I do think that we should try to make it clear that changing where your Q# program starts is as easy as moving the @EntryPoint() attribute to another operation, no renaming required. :)

@gillenhaalb
Copy link
Contributor

I would absolutely agree with @samarsha. I don't think the familiarity to other languages will have much particular benefit, because I can't imagine "add @EntryPoint() where you would like your program to start" being too much for a newcomer to wrap their head around. If they're familiar with Main from other languages, they'll likely think internally "oh okay it's like Main" and move on without a hitch; but if they're not, the whole thing could become very confusing, very fast.

Additionally, I think the confusion of when to rename each entry point operation would go well beyond a few additions to the style guide. Considering that interop allows calling multiple Q# operations from the host program, would the Main renaming be isolated to when using the standalone executable?

  • If so, that further shrinks the parallel between the host programs and standalone. For the docs (including tutorials, etc.), this would mean confusing additions where we currently have simple instructions along the lines of "the only change necessary is adding @EntryPoint() to your Q# file." In each context, we would further have to tell them that it's convention and not strictly required, potentially increasing the confusion.
  • If not, then the situation becomes even more confusing if their host program contains calls to different Q# operations; i.e. which is to be named Main if they're calling out to multiple.

Further, thinking about the potential path of Q# users and less about the simplicity of the docs, consider someone who has gotten familiar with Q# via the standalone executable, but now would like to start using a host program to export/plot their results. Instead of "remove the @EntryPoint() and call the operations by name from your host", the process becomes confusing in reverse, now requiring them to switch to descriptive names if they're calling multiple (for example to compare the results from two different operations).

In a nutshell: I'm of the opinion that the benefits of changing to Main are marginal (and would still not be reaped by all users), and that it would likely lead to confusion both in our docs and among users.

@cgranade
Copy link
Contributor Author

Re @anpaz-msft:

As you pointed out, I'm of the opinion we should use Main.
In particular, I suspect the EntryPoint should have the logic to run the program, and when you want to use a Q# operation from another Q# program you don't really want to call the entry point but its useful operations as the new program will have its own main logic.

I think that can often be the case, but we have seen examples such as recursive entry points for the postselected-qrng that speak to the "entry points as ordinary operations" view as well. I would suspect that would become more common if multiple entry points are allowed.

You covered very well pros of each approach, though, and as long as it's part of the style guide I don't have a strong opinion.

Thanks for your input, and for starting this discussion!


Re @geduardo (emphasis mine):

Interesting discussion. I don't have more pros for any of the options, but I do think that when accessibility and consistency with the style guide are confronted we should seek accessibility. Even at the expense of less consistent style rules. In general, many users don't follow strictly the style guides. We want to make the language as accessible as possible to get broader audiences. Familiarity with other languages is always a very strong feature for accessibility.

This is a good point, but I honestly think this pushes more towards entry points as ordinary operations; if we think people won't consistently use the name Main, then having a mix of Main and other names could be more confusing than teaching what @EntryPoint() does.

So I'll go for Main(), but don't take my opinion very seriously since I'm just a noob in computer science and programming languages!

I really appreciate your input, @geduardo!


Re: @samarsha

I think that other languages originally used Main because they didn't have another way to tag a function as being the entry point; the name was hard-coded. In Q#, the name doesn't matter, and while following conventions from other languages can make Q# easier to learn, I don't think this is one of those cases. I think that using Main when it is unnecessary can actually create confusion, because users coming from languages where Main is required may see it in Q# and think that it is also required, when actually the @EntryPoint() attribute is doing all of the work.

This is a really good point; suggesting Main in the style guide may lead users to name an operation Main and then wonder why it doesn't work. I think the style guide should suggest conventions that guide users to the see that @EntryPoint() is doing the work, as you say, @samarsha.

Even in languages where the name Main is not required, you could still argue that you should call it Main because it is the only function that has to directly handle parsing the command-line argument string, before handing off the arguments to a normal function. But that isn't true in Q#, either. Q# entry points are strongly typed, and their parameters are the same as any other operation.

Agreed, we don't want Q# users to have to worry with args : String[], after all. I think the conventions set by System.CommandLine.DragonFruit confuse this slightly, but given that's still an experimental package, I agree that the overwhelming interpretation of the name Main isn't just "entry point," but "entry point that takes a bunch of strings representing command-line arguments."

IMO, a good Q# entry point should be indistinguishable from other operations, and the name should reflect that. I don't know if Q# should support multiple entry points, but I do think that we should try to make it clear that changing where your Q# program starts is as easy as moving the @EntryPoint() attribute to another operation, no renaming required. :)

Tangenting slightly, I do think multiple entry points would be a really good future addition, similar to how CUDA projects can expose multiple executable kernels. A host program may decide during the course of its workflow to dispatch Q# applications with fundamentally different signatures to target machines, such that exposing them through multiple entry points could make a lot of sense. Consider a QML workflow, for instance, with training and classification steps; these would share a lot of internal code such that collecting them in one project makes sense, but they would still be called with fundamentally different input signatures.

Having a naming convention in our style guide that allows for this future extensibility seems like a good idea to me.


Re: @gillenhaalb

  • If so, that further shrinks the parallel between the host programs and standalone. For the docs (including tutorials, etc.), this would mean confusing additions where we currently have simple instructions along the lines of "the only change necessary is adding @EntryPoint() to your Q# file." In each context, we would further have to tell them that it's convention and not strictly required, potentially increasing the confusion.

I think this in particular speaks to @samarsha's point that entry points should be ordinary operations, including in terms of the style guide.

  • If not, then the situation becomes even more confusing if their host program contains calls to different Q# operations; i.e. which is to be named Main if they're calling out to multiple.

Further, thinking about the potential path of Q# users and less about the simplicity of the docs, consider someone who has gotten familiar with Q# via the standalone executable, but now would like to start using a host program to export/plot their results. Instead of "remove the @EntryPoint() and call the operations by name from your host", the process becomes confusing in reverse, now requiring them to switch to descriptive names if they're calling multiple (for example to compare the results from two different operations).

In a nutshell: I'm of the opinion that the benefits of changing to Main are marginal (and would still not be reaped by all users), and that it would likely lead to confusion both in our docs and among users.

@geduardo
Copy link
Contributor

geduardo commented Jun 11, 2020

Re: @samarsha

I think that other languages originally used Main because they didn't have another way to tag a function as being the entry point; the name was hard-coded. In Q#, the name doesn't matter, and while following conventions from other languages can make Q# easier to learn, I don't think this is one of those cases. I think that using Main when it is unnecessary can actually create confusion, because users coming from languages where Main is required may see it in Q# and think that it is also required, when actually the @entrypoint() attribute is doing all of the work.

This is a very good point!

Even in languages where the name Main is not required, you could still argue that you should call it Main because it is the only function that has to directly handle parsing the command-line argument string, before handing off the arguments to a normal function. But that isn't true in Q#, either. Q# entry points are strongly typed, and their parameters are the same as any other operation.
IMO, a good Q# entry point should be indistinguishable from other operations, and the name should reflect that. I don't know if Q# should support multiple entry points, but I do think that we should try to make it clear that changing where your Q# program starts is as easy as moving the @entrypoint() attribute to another operation, no renaming required. :)

Mmm, while I agree that moving the @EntryPoint() attribute it's a handy feature, I've some concerns with regards if it's going to be used in that way by the users. In my experience with the Q# standalone (and other languages in general), the structure of the programs is almost always:

  • Secondary operations.
  • A main operation that makes use of the secondary operations defined above (or in other files) and prints out the desired result of the computation.

Given the purpose of quantum computing (and therefore of Q#), that is mainly to be used to compute hard operations, I think this structure will prevail and the feature of changing the @entrypoint() might not be as used as we expect.

But I agree, having the @entrypoint() attribute and also having the convention of naming the main function as Main can create some confusion to the user.

@tcNickolas
Copy link
Collaborator

I'll vote for entry points as ordinary operations and not reiterate the points folks have made above :-)

@cgranade
Copy link
Contributor Author

Given what seems to be the consensus from the discussion so far, I'm happy to say let's go with the "entry points as ordinary operations" alternative unless either @anpaz-msft or @geduardo has strong opposition.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants