-
Notifications
You must be signed in to change notification settings - Fork 424
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
Chapel standard module style guide (collecting input) #6698
Comments
Michael's input for the style guideSingle NamespaceStyle guide should note many of these decisions are there to aid developers in working with the fact that Chapel is single-namespace language. CamelCaseGenerally, prefer CamelCase or camelCase to separating_with_underscores. Style of Identifier Names
Method Names and Part-of-SpeechOne of the nice things about a well-designed method names is that it's easy to mentally translate from a method call into a sentence. For example, Field names can be nouns. Some methods are sortof accessors or similar to them. In that case I don't have a problem with using a noun. I think that In the case of
In other words, if I was writing complete English sentences in my programming, Module Naming vs Type NamingWhen creating a module that mainly exists to define a single type, how should one choose the type name and the module name? I think we should use the convention of making the module name a more specific/spelled out version. Examples:
I think that this is a useful and reasonable convention because the module name seems to me to be more likely to be visible as introductory material:
And, at the same time, I would expect the module name to appear fewer times in user code than the class name. Thus it is less troublesome for the module name to be longer. (It is true that some users might opt to write something like BlockDist.Block everywhere; but such users are opting in to verbosity and there is an obvious way to reduce it). |
Michael's list of things that "stick out"
|
Some patterns that might benefit from a stylistic recommendation
sort(A);
// vs.
A.sorted();
A.dims()
// vs.
A.shape |
I think the method versus function question falls under general programming practices (regardless of language with objects). My recommendation for parentheses vs. parentheses-less methods is:
|
I have sometimes wanted consistency between using primary or secondary methods on classes (or records, or unions). For example, // bar is a primary method
record Quux {
...
proc foo(...) {...}
} vs // bar is a secondary method
record Quux { ... }
proc Quux.bar(...) {...} Stylistically, my preference is for:
However, secondary methods on classes defined in the same module are common; e.g., |
In Java and Python, there is disambiguation on the package level, so |
@LouisJenkinsCS - single namespace really means that attention should be paid to the names of top-level modules as they need to be reasonably unique. So in your example, literally parentModule is probably not a reasonable top-level module name, and neither is Test or Project but something more project-name-y like Hypergraphs or SuperIO is good. Nested modules don't have this issue and are reasonable to use and can have less unique names. |
I'd expect |
A few others:
Many modules that exist as a thin wrapper around some C library will use naming schemes from the original C library, e.g. FFTW or Curl. It seems reasonable to leave these as is. |
By this definition, what's an example of a popular non-single-namespace language? I worry (as I think Louis did above) whenever someone uses this term out loud that what everyone hears (myself included) is that all Chapel identifiers are thrown into a single namespace with no hierarchy, scoping, etc. What I think the term has traditionally been intended to be used for w.r.t. Chapel is to say that we don't treat identifiers of one kind differently than identifiers of another kind (i.e., there isn't a collection of function names distinct from the collection of variable names). |
Certain interpreted languages manage "imports" by file path. In these languages, you can have multiple "top level modules" with the same name as long as you point to one or the other with the import. I'm not sure I have a great example at the ready but one example is that in Python you can manipulate the Python path just before (and also maybe after) doing an import. Other examples (for interpreted languages) of reading code from a file:
I agree that this is the proper definition of "single namespace". Originally, I used the term because we need a different identifier for a module name, a class, and a function. Anyway, this is a good clarification in this discussion. |
Regarding the names of types: Earlier I said this:
@bradcray responded in #13030 (comment) :
I find the "User-defined" vs "Internal" types to be rather confusing (RandomStream and Timer come with the compiler, so aren't they thus "internal"?). I would prefer a rule that would allow Chapel programmers to emulate the style they see in the standard library, since that's probably what they will do in any case. So, if we choose "internal types are lower case" then I'd prefer that to apply only to a small number language-specified types that the compiler knows about (e.g. I'd also consider having a rule that all types are UpperCamelCase, including Today we have |
Rust actually makes a distinction between identifiers on modules and structs, etc. and identifiers on variables and functions because the former identifiers are unambiguously referenced with mod thing {
pub fn doit() {
println!("fn thing::doit()");
}
}
fn thing() {
println!("fn thing()");
}
// This global variable, however, does not work; `thing` is already used by `fn thing()`.
// static thing: &str = "variable";
fn main() {
thing();
thing::doit();
} This code behaves as expected. |
One source of (minor) confusion that I have coming from a C/C++ background is the specification of a function's arguments versus the cast operator. Just a very minor confusion, but it does affect my ability to quickly scan through a piece of code. proc doSomeIoOperation(x: string) { ... }
// ^------- type specification
proc main() {
var x: string = readFromFile();
// ^------- type specification
doSomeIoOperation(x: string);
// ^------- cast operator
proc doOtherIoOperation(x: string) { ... }
// ^--- denotes procedure ^------- type specification
} Whenever I do a cast, I've taken to the habit of binding to the RHS side instead. var a = 42;
var b = a :real;
writeln(b.type :string); |
Building on what Michael said above and (I think?) agreeing with him:
So if I ran the world, I'd say "records use initialLower and classes use InitialUpper," and then fall back to "all types use initialLower" if that wasn't palatable. I'd be curious if anyone strongly disagreed with this stance. |
Definitely not. My objection is specific to the proposal that value types be lowerCamelCase and class types UpperCamelCase. I am fine with, for example, a convention that type names are lowerCamelCase and module names are UpperCamelCase, because there the minor lexical difference is augmented by the syntactic cues due to usage. I would even be fine with a convention that type names were lowerCamelCase but class type names had a
👍 Yes, for sure if we have a convention we should have a checker for it. |
This seems like splitting hairs to me. In some cases (particularly
If we have a checker for the convention, then does that eliminate the chances of willful or inadvertent surprise and put us back onto stable ground if we were to adopt a class vs. record naming convention? |
Sure, that sounds reasonable. |
Michael reminded me to kick in my 2¢. To me, type inference makes a language easy to write but difficult to read. It takes me a long time to trace back through the code to find out what something is. Visual cues help to reduce that problem. For that reason, I prefer that classes begin with an upper case letter unless they are internal-enough types like string, and most other things begin with a lower case letter. It is probably well known that to me, camel case is an abomination. |
It seems the idea of records/by value types use lowerCamelCase and classes/by reference types use UpperCamelCase has enough support provided that there is compiler enforcement of it within the standard/internal modules. |
I'm for differentiating cases that should be differentiated, but I imagine this might be a (mild) concern when users begin to refactor codes.
As such, I think I'd advocate for types to always be UpperCamelCase. ... (Which conflicts with module naming conventions, but that's a different issue.) But this is just my opinion which could be wrong for large-scale production codes. Some of these naming-convention distinctions would be resolved by a decent IDE. |
Should there be naming conventions for in-place vs. out-of-place operations? The proposal to deprecate |
These documents have some interesting discussion of part-of-speech naming (noun vs verb etc): |
See also Property queries: paren-less or paren-ful? #17128 |
Over on the review of #17936, Andy asked if we had a specific policy on the capitalization of initialisms and acronyms:
|
I always wrestle with this question, though the variant I wrestle with is if I choose the That said, I feel like I'd want to see more cases in practice to decide whether I'd feel different in different situations (i.e., whether I think this should be a hard and fast rule for standard modules, or whether we'd want to let authors choose based on taste). |
One way would be for the acronym to be uppercase unless another word follows it; so |
Over in #19012 (comment) Damian brought up a potential rule for operator-like names - that they be treated as a single word for the purpose of camelCasing. So for instance, |
Over on #14291, we solidified our discussion on factory functions to the point where it can be included:
|
I might phrase this instead as "being sufficiently better/clearer in practice to garner a lot of support." That said, both David's seem to be more on the "prefer type method" side of the equation, so we may want to make sure we're not squashing voices by having louder ones assert something that a silent majority doesn't agree with.
I wouldn't even call these factory functions. I'd describe this caset as "Some routines exist to do things and the result of doing that thing happens to create a new object." For example, I wouldn't say that |
This issue is meant to collect:
Having a style guide and adjusting the user-facing Chapel APIs to adhere to it addresses a language stability concern. There are two reasons for that:
The style guide would simply represent some best practices for API design in the context of Chapel modules. Of course there will be situations in which there is a good reason to make an exception to it.
Please add any requests for the style guide or API issues that "stick out" in the comments on this issue.
The text was updated successfully, but these errors were encountered: