Relies on #1047 being implemented:
@typeOf(x) == type or x is a function returning type then x should be TitleCase"@typeOf(x) == type and std.meta.fields(x).len != 0 or x is a function returning y where @typeOf(y) == type and std.meta.fields(y).len != 0, then x should be TitleCase"TitleCase name: Namespace.func()snake_case name: instance.method()instance is passed by copy, *const or *).Thing.func(&instance).snake_case and camelCase names are taken up by std, keywords and my own namespaces (the following list is words I've wanted to use for variables and functions before, but couldn't without then prefixing my namespace).std: mem, json, mutex, event, drawfsection, align, type, and, or, export, error, catchslice, platform, scan, bits, parser, string, compareTitleCase names are rarely declared, and single word snake_case and camelCase names are extremely common.Just to get a little preview of what this would look like:
const Std = @import("Std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
const stdout_file = try Std.Io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");
}
I do think that looks nice.
Std.Io.getStdOut()
I propose that acronyms are capitalized in the traditional way when used in a TitleCase context. Ex: IO instead of Io, HTTP instead of Http, etc. So, Std.IO.getStdOut() in the above example. A hypothetical long form would be InputOutput. A hypothetical shortened form would be InOut. Following that, I think IO makes sense.
@jayschwa I broadly advise against that convention. You wind up with names like XMLHTTPRequest and JSONRPC where you can't identify initialism boundaries without prior knowledge. This can be a nuisance for code generation; e.g. converting a type name to a function name might result in make_xmlhttp_request instead of make_xml_http_request. For consistency, I suggest avoiding this style anywhere in code, including in namespaces.
tl;dr; UpperCamelCase frustrates when using abbreviations or acronyms, which as it so happens, is the most popular for namespace-names.
my 2 cents as a zig newcomer: NO to UpperCamelCase namespaces:
Premise assumptions and broad strokes about a namespace-name:
std.io.debug.warn()
cstr.toSlice()
json.Parser.init()
dynamic_library.LinuxDynLib.open()
| | DESCRIPTION |
| ---- | ----------- |
| β | appealing abbreviation identifiers; eg. std |
| β | appealing acronym identifiers; eg. io |
| β | appealing word identifiers; eg. debug |
| ΒΎ | appealing multi-word identifiers; eg. dynamic_library |
| ΒΌ | appealing when using numeric suffix; eg. { sse2, ipv6 } |
| π | infer is(method-call)? vs. is(function-call)? by looking to LHS of dot-operator |
| π | avoid collision with lowerCamelCase/snake_case (functions, parameters, variables) |
Std.Io.Debug.warn()
Cstr.toSlice()
Json.Parser.init()
DynamicLibrary.LinuxDynLib.open()
| | DESCRIPTION |
| ---- | ----------- |
| π | appealing abbreviation identifiers; eg. Std |
| π | appealing acronym identifiers; eg. Io |
| β | appealing word identifiers; eg. Debug |
| β | appealing multi-word identifiers; eg. DynamicLibrary |
| π | appealing when using numeric suffix; eg. { Sse2, Ipv6 } |
| β | infer is(method-call)? vs. is(function-call)? by looking to LHS of dot-operator |
| β | avoid collision with lowerCamelCase/snake_case (functions, parameters, variables) |
Std: in english print, a mixed-case abbreviation is rare compared to all-lower-case.Standard; I don't support this because prefer shorter and more convenient as compared to type-name preferencesSTD; I don't support this because it becomes special treatment for abbreviations and confuses readability with multi-word namesIo: in english print, a mixed-case acronym is rare compared to all-caps or all-lower-case for very common acronyms.InputOutput; I don't support this because prefer shorter and more convenient as compared to type-name preferencesIO; I don't support this because of the _commonality_ of namespaces and readability with multi-word namesStd.IO.Debug.warn()
Cstr.toSlice()
JSON.Parser.init()
DynamicLibrary.LinuxDynLib.open()
STD.IO.Debug.warn()
CSTR.toSlice()
JSON.Parser.init()
DynamicLibrary.LinuxDynLib.open()
@mikdusan Acronyms already lose there casing in type names according to the current styling so unless you propose that this is also changed, then I don't see this as an argument against changing 'namespace' to be TitleCase.
// Taken from the "Style Guide" section in Zig's documentation
// The word XML loses its casing when used in Zig identifiers.
const xml_document =
\\<?xml version="1.0" encoding="UTF-8"?>
\\<document>
\\</document>
;
const XmlParser = struct {
field: i32,
};
Type names rarely contain abbreviations so I don't know what is preferred here.
I will say, that it is hard to argue for or against "appeal". It is very subjective and all I can really say here is, that I find Std and Io just as appealing as std and io. I'm not writing an English paper, but a program so I don't mind if we break a few 'rules' in the English language to get the practical benefits that I point out in my proposal.
@Hejsil,
Acronyms already lose there casing in type names
I don't think that's an argument for changing to TitleCase; rather the opposite; because the type-style discourages(?) all-caps of sub-words in TitleCase; eg. XmlParser is evident and XMLParser is not; tech-print (I'll call it that instead of english-print, meaning to include docs/specs in multiple-speaking languages) mostly likes acronyms which are all-caps or all-lower-case. Doing XmlParser is contrary to this tech-acronym-rule (TAR). If this were a namespace with acronym+words then I'm advocating:
xml_next_gen > XML_Next_Gen > XMLNextGen > XmlNextGen. There are many examples of TAR that work well and commonly, as either all-caps or all-lower-case, but (again subjectively) look awful when TitleCase'd.
| UP | DOWN | Title |
| --- | --- | --- |
| BBC | bbc | Bbs |
| DTS | dts | Dts |
| USA | usa | Usa |
| OEM | oem | Oem |
| ROM | rom | Rom |
| RAM | ram | Ram |
| DDR | ddr | Ddr |
| DDR4 | ddr4 | Ddr4 |
| SSD | ssd | Ssd |
| HDD | hdd | Hdd |
| MP4 | mp4 | Mp4 |
I think there is a reason why those acronyms are seen in tech-print almost exclusively as TAR... if I may be so bold to suggest it's because the public at large, including programmers, find it easier. For whatever reason, it is easier and that has value.
I'm not writing an English paper, but a program so I don't mind if we break a few 'rules' in the English language to get the practical benefits that I point out in my proposal.
My argument is not really about sticking to english rules. Rather it's that we understand it is a basis, and has influence over the readability of source code. It is a plus, I think, when we can keep some consistency to TAR.
- Simpler rule
- Clearer function vs method call site
More available names for parameters, functions, and variables (which is the names you'll be writing the most)
My proposal:
"If
@typeOf(x) == typeorxis a function returningtypethen x should be TitleCase"Current (after namespace changes):
"If
@typeOf(x) == type and std.meta.fields(x).len != 0orxis a function returning y where@typeOf(y) == type and std.meta.fields(y).len != 0, then x should be TitleCase"
On a side note, the rule as listed "current" doesn't appear to match Zig online docs. I read the docs like this:
@typeOf(x) == type and std.meta.fields(x).len != 0 or x is a function returning y where @typeOf(y) == type, then x should be TitleCase"Thank you Hejsil for responding. I'm pretty sure there isn't much more I can say except that I agree there is significant subjectivity. It's not clear to me that I'm late to the game on providing input, but regardless, I'm happy with the way Zig is progressing and whichever way this goes it won't be a show-stopper for me.
@mikdusan You seem to have a good idea of common practices in these areas of writing. I would agree that I too tend to see this TAR style more often than not (I think, I don't keep track) when reading 'tech-print', but it doesn't seem to be a standard (I can't find any information about TAR). Wikipedia has a section about caps styles, and from what I can read here, the choice is mostly stylistic.
I don't have the same source for abbreviations, but I think it's mostly a stylistic choice as well. I'd never write Util and Interop in all-caps.
I also know that C# uses the proposed style for namespaces, but most languages similar to Zig uses snake_case (Rust, C++, Go).
Edit: Also, you're not late at all on this issue. Until it has been accepted and applied, the discussion can and will continue :)
I don't have a concrete counter proposal to this issue at the moment, but I want to say that I agree with @mikdusan's breakdown in https://github.com/ziglang/zig/issues/1884#issuecomment-469572968. I think it clearly demonstrates the pros/cons of status quo as well as this proposal.
In particular, there are a few identifier names in the standard library that feel "wrong" according to status quo style guide (things like XmlParser, especially when "XML" is one letter such as "C"), and it's tempting to break away from the style guide. However I'm also not a fan of Std.Io. I want to encourage namespaces, and offering a quick way to type them is one way to do that. I fear the annoyance of the shift key will make more people want to use usingnamespace (#2014).
Here's an example from standard library that is awkward:
pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
self.verbose_cc = value;
}
The lower case one looks good. "Verbose C Compilation". cc is a command on most systems.
The camelCase one looks wrong, and setVerboseCc looks even wronger :-1:
But as is this example represents cognitive dissonance, because if the fn name and the field were to match, then it would have to be setVerboseCc/set_verbose_cc or setVerboseCC/set_verbose_c_c. I don't want people (myself included) to get distracted by cognitive dissonance of naming things. So that's a reason why status quo is flawed. Note, I don't necessarily consider this proposal to be an adequate solution. Just admitting there is a problem.
setVerboseCc/set_verbose_ccorsetVerboseCC/set_verbose_c_c
more 2Β’; in consideration of article Camel case:
and those are some pretty good general rules. But it's not clear enough for more complex cases that coding runs into. The following guidance is more or less my preference style to clear things up:
exe works fine classified as a word; usually seen prefixing real words| delineation | tokenized | types | callables | other | note
| --- | --- | --- | --- | --- | --- |
| set, verbose, CC | word, word, acronym || setVerboseCC | set_verbose_cc |
| IR, builder | acronym, word | IRBuilder | irBuilder | ir_builder | UpperCamelCase acronym+word is usually ok |
| LLVM, MC, JIT, compiler, options | acronym, acronym, acronym, word, word | LLVM_MC_JIT_Compiler | llvm_MC_JIT_Compiler | llvm_mc_jit_compiler | camels needed help with consecutive acronyms |
| compile, exe | word, word | CompileExe | compileExe | compile_exe | exe treated as word |
These styles become much easier to visualize with a table. A good style guide would show simple, medium and complex examples to help readers reach the same naming conclusions.
I think Std.Os.Path.resolve is noticably slower and more painful to write than std.os.path.resolve, at least on my keyboard layout (I don't have to press shift to get a dot, but I do need it for uppercase letters). That's more noticable than "looks nice" IMO. It doesn't matter so much for other things than namespace names, because they contain less uppercase letters.
Some stdlib module names were TitleCase in Python 2, but they were all changed to lowercase in Python 3. Most other languages use lowercase names for namespaces too, so maybe people will find it more familiar. Also, Thing.func(&instance) looks to me like Thing is a struct, and func is a function defined in it, and not at all like Thing is a namespace.
Could a scope-resolution operator e.g. :: be introduced for accessing "static" struct members (including nested struct definitions)? Type definitions are comptime-only, roughly equivalent to "static" in other languages so it may be semantically justified to have a separate operator for them.
const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
const stdout_file = try std::io::getStdOut(); // getStdOut() accessed via :: because it doesn't take an implied *self param
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");
}
Pros:
const/"static" member over an instance member, which is important information when writing codeCons:
Why was this closed? Was it rejected? If so, what was the reason? I just want to make sure I'm staying up to date on what's going on with Zig and I feel like I missed something here.
Yes, if a proposal is closed that means it is no longer being considered. Have a look at the comments in this thread. @mikdusan's comments in particular are quite clear.
Most helpful comment
@jayschwa I broadly advise against that convention. You wind up with names like
XMLHTTPRequestandJSONRPCwhere you can't identify initialism boundaries without prior knowledge. This can be a nuisance for code generation; e.g. converting a type name to a function name might result inmake_xmlhttp_requestinstead ofmake_xml_http_request. For consistency, I suggest avoiding this style anywhere in code, including in namespaces.