[0] https://nim-lang.org/docs/manual.html#lexical-analysis-ident...
[0] https://nim-lang.org/docs/manual.html#lexical-analysis-ident...
So MyNimName, mynimname, MY_NIM_NAME, My_Nim_Name, __MYNIM___name_, and any other variation you can think of are all the same name!
Most search tools have the option of case sensitive or insensitive search, but a search that does that and ignores underscores? Not too many of those outside the Nim world.
An interesting contrast is Nim's policy on tabs and spaces for indentation.
Spaces are fine. You can use as many as you want. Two, four, three, whatever. Nim doesn't care.
But Tabs? They are forbidden!
Unless you use this magic line at the top of each source file:
#? replace(sub = "\t", by = " ")
Now you get to use tabs!In any case (pun intended?) it's the underscore insensitivity that makes it difficult to use standard search tools.
I personally don't like the feature, but what do you find difficult about using /my_?[vV]ariable/ to search for any of myvariable, my_variable or myVariable?
The motivation is good, if the intent is to get rid of ___unwanted___crap___ like this.
But if I, as a language designer, wanted to ban such identifiers, I would just go ahead and ban them, rather than making them equivalent to ones that do not have repeated underscores.
The principle is: don't make unwanted/undesirable forms equivalent to acceptable forms in hopes that people will then just stick to the acceptable forms when they discover that the the unwanted forms don't bring about the difference they were hoping for. People won't. People will go to town with the equivalence to make problems for other people.
People who don't know about the equivalences, or have forgotten, will be tripped up. Someone might think that a variable called __foo in an inner scope is different from an outer (or global) _foo, yet their definition will shadow _foo, with some behavior-altering consequences.
Nim does not allow variables starting with underscore.
Also, the compiler errors cannot if any of "useHTTP", "usehttp" or "use_http" is acceptable or unwanted, but it can error out with a clear warning if you are trying to define different variables with those names in the same scope.
From a theoretical perspective, your argument can equally be applied to C's case sensitivity or Pascal's case insensitivity when someone "doesn't know" or "forgets" about the equivalece - isn't it absurd that FOO and foo are different (C) / equivalent (Pascal) when you are coming from the other one? Similarly, Lisp-1 vs. Lisp-2 . In practice, it's just one more convention -- among several others.
The motivation is not to get rid of __unwanted___crap___ (nim bans multiple sequential underscores and leading underscores, so they are rid of), but rather: Nim arguably has the best built-in FFI of any modern language with nontrivial use, and this FFI has been a factor in the language design. Nim's rules allow you to keep a mostly uniform coding style in _your_ parts, yet integrate it naturally into projects using snake_case, CamelCase, javaCase and ALLCAPSCASE and SHOUTING_MATCH_CASE, or all of the above in the same project.
Nim started out case-insensitive (which is less popular, but definitely common choice made e.g. by Pascal, Excel and others). IIRC, the "first letter's case does matter" is a relatively recent addition (as in, 2 years out of the project's 9) to simplify FFI to conventions like OpenGL, which have the same identifier in both lower or upper case.
In theory, everything could go wrong. In practice, Nim gets it exceptionally right.
If so, that's an incredibly bad idea.
If a program calls some foreign function called FooBar, the identifier FooBar better appear somewhere in it, if you know what's good for the maintainer seven years from now.
Again, the theory can be argued endlessly. In practice, it just works.
If it's just some construct that defines a call to FooBar in the foreign library, with no mention of foo_bar, but elsewhere in the Nim code we call it as foo_bar, I'm afraid I cannot agree with this being a good technical decision in language design.
I wouldn't sign off on such a concealment ruse even if it were someone's macro, not being upstreamed into a language implementation at all.
You don't have to agree, you don't have to like it, you don't have to use Nim, and you don't have to think it's a good idea. But any reasonable sampling of real world use shows that it's not a bad technical decision. I don't think it shows it's a great technical decision either; It just shows that it's acceptable and comparable in mental and operational burden to any other decision.
It seems whether it is a little better or a little worse, it will take years of experiment to get any kind of statistical significance.
Well, a nim name; there is no the nim name.
> you don't have to use Nim,
That would be the lucky situation for now; if we band together and write cogent criticisms, we may be able to keep it that way going forward.
You shouldn't modify code in a programming language you don't have sufficient familiarity with - at least not code that you depend on.
C has shortcut boolean ops, so "if (have_peace_treaty || launch_missiles() == LM_SUCCESS) cross_border()" would not launch missiles if you have a peace treaty.
C++ has shortcut boolean ops as well... unless you have overloaded "operator&&". So the same line in C++, depending on the types involved, might not short-circuit and start a war even if you have a peace treaty.
In Pascal and Python 3, evaluating 1/(1/2) gives 2. In python 2 and C, you get an integer overflow (with differing semantics). But 1.0/(1.0/2) gives 2 in all cases, even though 1==1.0 is true in all languages mentioned.
And "if (0.3*3 == 0.9) all_is_well(); else apocalypse_go_to_bunker()" might also surprise you if you are not aware of how FP math is implemented (in APL/K/J, all_is_well(), but not in any other language I'm familiar with).
The only example I can think of that could bite you is when shadowing an outer scope -- which is just as much a problem in C, Python etc. Some compilers warn about it, some don't, I don't know if Nim does.
In practice, Nim choices put it in an amazingly sweet spot.
It's not as if some non-user of Nim announcing they'll avoid the language is any great loss.
Reminds me of all those "Cancel my subscription" letters to the editor in days past. Yeah, I'm the the "Time" magazine or whatever would tremble to know someone is cancelling...
I feel most people who read about style insensitivity imagines all Nim code being written as a crazy mix of styles, while in reality Nim code is often more consistent in style.
And the tabs vs. spaces issue is simply to alleviate the issues with "how many spaces are a tab" which is impossible to guess when compiling code. The replace filter you mention above essentially just explicitly specifies how many spaces you intend a tab to be. That being said I would've liked it better if it forced tabs, that way you'd have one tab for one indentation level, and everyone could choose their own preference of indentation.
The problem with this is that in many code bases, you occasionally need spaces to align code/data in different lines to make them more readable and easily inspectable, e.g. within a long parenthesized expression spanning multiple lines. In that case, indentation tabs require nontrivial gymnastics, whereas spaces are consistent.
The files should always contain spaces - because behaving as if spaces are tabs is round-trippable even when every user uses a different setting. An editor could en-tab on load, de-tab on save, and everyone is happy (though I'm not aware of any editor that does this). If the file only has tabs, the converse "de-tab on load and en-tab on save" does not give you the same alignment flexibility.
Nim takes a practical approach by banning tabs altogether; The "#?" hack you suggest just shows another great Nim feature - source code filters are standardized; You don't need a preprocessor/lex/yacc/re2c/swig with its own driver/makefile; it's all well documented and tracked within your Nim environment.
[0] especially in languages in which indentation changes program semantics, but even in e.g. C - where mismatch between indentation and curly brackets can let a bug like "goto fail;" hide in plain sight.
I think that case insensitivity actually does make sense when working with symbolic identifiers. I've seen justifications for "Foo" and "foo" being distinct symbols; personally, I find that playing with casing like that reduces my ability to read code quickly.
Case insensitivity does have its downsides, but usually it's not as noticeable in VB.net because most development is done in VS, which automatically re-cases symbols to match the original definition.
[1] Number 6 based on search engine popularity according to https://www.tiobe.com/tiobe-index/ Also, anecdotally, it's used quite a bit in industrial automation.
Case insensitivity is a feature and it's meant to allow easy interfacing with C.
And it also encourages clean code.
With other languages you can have variables called "startdate", "start_date" and "startDate" in the same scope leading to bugs - especially when using completion in an editor - and poor readability.
In Nim the compiler tells you that you are redefining the same variable in 3 different places and you can go and give them more meaningful names.
If this is the goal, there are many alternative ways to solve this problem, making the language case insensitive is a pretty big hammer.
There is a reason old languages were many times case insensitive but not anymore.
Regardless, this does not preclude the use of Nim any more than a regulation saying "do not use preprocessor macros" preclude C because you might accidentally use #define. It just means you have to verify that you adhere to those regulations. Here's one tool[0] you can use to make sure your unconditional requirements are satisfied.
Nim would probably be precluded anyway based on age and popularity, and rightly so for tightly regulated industries -- but given some time, assuming it does grow in popularity, there is no inherent reason Nim would be precluded from any project that allows e.g. C++, Java, JavaScript or Go.
As an aside, is there some reason that using the same identifier with different cases is desirable?
You could ban using the same identifier with different cases, instead of treating them the same.
And Nim is one of those languages too. This is perfectly valid and frequently used:
type
Person = object
name: string
age: int
let person = Person(name: "you", age: 99)
echo person
You can try it in Nim Playground: https://play.nim-lang.org/#ix=20jS auto * logger = Logger::getLogger("main");Question is, should the language enforce you giving your variables a better name, or should convention? I think there are reasonable arguments for both.
The language itself can't enforce better variable names, at least not this way - Nim doesn't stop me from using "abcd" or "a0, a1, ... a100" as variable names even though it's usually a very bad idea.
No, I think a language should help keeping the code consistent in the long term - and having this strange case insensitivity doesn't help there in my opinion.
Not at all. Style insensitivity encourages good variable naming and there are both formatters and also the simple text completion in editors to guarantee consistency.
This is NOT true.
The first character is case-sensitive in Nim, so examples like yours are not only possible, but frequently used even in Nim compiler and standard library.
It is mostly for conventions, however different cases are generally used to represent different things. For example, in Python:
- ALL_CAPS: global variables
- PascalCase: for classes, and now that Python has typing annotations, types
- snake_case: everything else, from variables to function/method names
(This is not a rule, Python allows anything anywhere, so it is just a convention).
So for example, in Nim you couldn't have PERSON (global variable) and Person (class), however you could still have Person (class definition) and person (class instance). Of course, applying the code style from a language to another language is silly, however it is just to illustrate the value of case sensitive identifiers (if you think that my example is more or less valuable than having the flexibility of using a external library the way you want this is your choice).
BTW, nowadays I am studying Golang and I found it annoying that you capitalization is meaningful in Go, so person() is a private function however Person() is public. It is generally not bad, however sometimes I want to create a global private constant and can't simple call it MY_CONSTANT since this would make it public.
It's not like that. The thing is that having case insensitive identifiers incentivices people to be inconsistent with their casing "because it doesn't matter" as one coworker that works in a case insensitive language said to me. "Whoops, I wrote 'vALUE'. Well, it doesn't matter; it works. :)" Thank god I don't have to touch that codebase. I do wonder on average how many different variations of casing is used for each variable and keyword.
Yes, there are always people who would do stupid stuff.
But we have decades of experience with Pascal, SQL, VB, VB.Net, Excel and variety of other languages. Decades. They each have their problems, but in wide practice, case [in]sensitivity is not one of them.
Of course, many people are going to be consistent with their casing even when using a case insensitive language, but it's nice to know that particular forms of bad style are never going to be an issue because particular rules of good style are enforced by the language.
inconsistent tab/space use is a problem in practice (not a "wide" one in my experience, but not negligible), but if you use the right tab width (and many projects mark it inside the files with a hint e.g. Emacs understands so that won't be an issue) - then it becomes a non problem too.
I've never heard of someone saying "I don't care about mixing spaces and tabs because it's the curly braces that matter", and I've never heard of someone who edits a file with inconsistent on-screen indentation and doesn't care.
Alright, I was talking about the latter, which causes the former when you're not evaluating file modelines.
> not a "wide" one in my experience
I have a ~/build directory that contains source files of 207 projects whose source I've downloaded over the years for various reasons. Of those 207, if I look for mixes of tabs and spaces in indentations using:
for p in ~/build/{pkg,repo}/*; do
grep -IPlr '^\s*( \t|\t )' $p/^.git | head -1
done | wc -l
I get 144. You may consider the pattern `\t ` ok though because some people think it's cool to use tabs for indentation and spaces for alignment, but if I exclude those: for p in ~/build/{pkg,repo}/*; do
grep -IPlr '^\s* \t' $p/^.git | head -1
done | wc -l
I still get 110. Now, those are just the ones that have a space and then a tab in one indentation. How about those that use a space as the first character in one indentation and then a tab as an adjacent line's first character in its indentation? for p in ~/build/{pkg,repo}/*; do
ag -lr '^ .*\n\t|^\t.*\n |^\s* \t' $p/^.git | head -1
done | wc -l
That's 142.If I run that last one only against pkg/, which contains mostly official package sources of my distro, then I get 69 matches out of 89 packages.
Note these are not file counts, but project counts with at least one such file.
You may view this as using a small sample size, but at least, the practice is pretty wide in my experience.
> but if you use the right tab width (and many projects mark it inside the files with a hint e.g. Emacs understands so that won't be an issue) - then it becomes a non problem too.
This isn't going to work when you're looking at a diff/patch, emailing an excerpt or otherwise looking at the code outside of a particular editor.
They could enforce case consistency instead of case insensitivity if that's the problem they're trying to solve, though.
Although, even then, consider that variables like 'inform' and 'inForm' might not mean the same thing...
Except you can't because Nim also ignores underscores in identifiers. Gotta make sure there is literally no way to disambiguate cases like this!
(I _want_ to like Nim but this single decision seems to me so spectacularly bad that it's a non-starter.)
Now, that does not mean Nim's underscore insensitivity is a good idea, but excuse me for saying "if that's a non starter for you to even trying, I have no respect for your opinion on programming language design". If you actually try and and dislike it, we might be able to discuss merits or opinions. "Ugly" it may be, it is in the eyes of the beholder. But "bad" - what's your metric?
I'm not sure I understand your argument. It seems to go like this: "Years ago some people said one of Python's design choices was terrible, and it turned out to be fine. So if you think a language's design choice is terrible, then I have no respect for your opinion."
I don't see how that makes any sense. (I mean, obviously you are welcome not to respect my opinions! But I don't understand the reason you give.) Some possible language design choices are terrible, no? To take some extreme examples, we can probably agree that the choices made by INTERCAL, Brainfuck and Malbolge are (deliberately) terrible. So, you surely can't actually think that thinking a design decision is game-endingly bad, as such, means having un-respect-worthy opinions.
Maybe what you actually mean is: Deciding not even to try using a language because of one design feature you find terrible is evidence of incompetence, and therefore if I do that then my opinions shouldn't be respected. But, again, surely that's obviously wrong; I don't need to try programming in INTERCAL to know that it's not going to be a good use of my time (unless as a joke).
My best guess (which of course could be wrong, and I welcome corrections) is that you mean something like this: "It should be obvious that this design decision in Nim is no weirder or worse or more unreasonable than Python's decision to make whitespace significant. Lots of people thought that was obviously unacceptable, and with hindsight we can see that they were silly. Since this feature of Nim is no more unreasonable than that feature of Python, you're being silly too."
But I think it's incorrect to say that this design decision in Nim is no worse than significant whitespace in Python. Or to say that I've no more reason to think it bad than people exposed to Python early in its existence. (I also think those people weren't necessarily silly if they thought significant whitespace was a terrible idea, though I think they were wrong to think that. I would not discount someone's opinions on programming language design merely because I found they'd thought Python's significant whitespace was a bad idea when they first encountered it.)
Nim's variable-name rules have the following consequences.
1. Standard tooling will do the wrong thing with Nim names. If you want to search your Nim codebase using grep, or index its identifiers using ctags, or find the next instance of a given identifier in the file you're editing with your favourite text editor, then you're out of luck. (Unless your favourite text editor happens to have added special-case support for Nim. Some editors do have some Nim support; e.g., there are packages for Vim and Emacs that do this. But there are some very basic things they don't do -- e.g., I would like the * key in Vim or C-s in Emacs to be able to search for identifiers in my code, and it doesn't look to me as if this is something the available packages provide.) Consider also searching on the internet; do you want to bet on Google and other search engines learning to interpret things that might be Nim identifiers according to Nim's rules?
2. There are some (admittedly rare) distinctions that there's simply no way to make in Nim identifiers. As an example, someone upthread mentioned "inform" versus "in form". I wouldn't expect this sort of thing to matter often, but as a matter of principle it seems to me extremely poor taste to have a set of identifiers that simply can't represent arbitrary short English phrases unambiguously. (It's a bit like in old versions of C, where compilers and linkers weren't required to be able to distinguish anything more than the first 6 characters of each identifier, case-insensitively. You can always work around it, but having such a restriction there at all is a sign that someone hasn't thought things through.)
These are genuine limitations imposed by Nim's identifier-name rules. There are obvious easy-to-foresee ways in which they would lead to inconvenience and trouble when using Nim. Of course, it might turn out that the advantages (in, e.g., letting you use external libraries with a variety of stylistic conventions, while keeping a single style for your own code) outweigh the disadvantages, in which case I'll have made a mistake in not wanting to pursue Nim further for this reason. I'm comfortable with that; I have a finite amount of time and have to choose somehow what things are worth spending the time to learn well, and inevitably sometimes those decisions won't be optimal.
So far as I can see, there is (and was in 1992) no objection to semantically-significant whitespace in Python that is (or was) as cogent as this. There was "it's weird and unfamiliar" (which, in fact, I think can be a perfectly adequate reason not to put time into something; again, time and effort are limited and one has to prioritize somehow), and "it makes copying and pasting more error-prone sometimes" (which I think was never a strong objection for anyone using anything smarter than Notepad for editing, because you need to be able to fix up indentation whether you have block delimiters or not), and that's about it.
So, to me right now, it doesn't look as if the situations are parallel. Of course I might be wrong! Maybe back in 1992 there were objections to Python's whitespace rules that were just as apparently-cogent as the objections above to Nim's identifier-name rules are now, and I've just forgotten what they were or how plausible they seemed. But I don't think so.
(Pedantic note: Python doesn't use indentation for scoping. It uses indentation to delineate block structure, and some languages that are not Python use block structure for scoping. Python's blocks do not in general create their own scopes.)
Feels like a poor design decision to me based on cost/benefit of user ergonomics.
I do it all the time, in numerical code. If you have two pairs of points, for example, it is very natural to name them "a,A,b,B"
And just to clarify once again, since I'm not sure who will read which reply: those are NOT the same identifiers in Nim!
let
a = 11
b = 22
A = 99
B = 88
echo a == A # false
echo b == B # false
Run the code in the Nim Playground if you don't believe: https://play.nim-lang.org/#ix=20krthen I don't really understand nim's case insensitivity rules
Think in reverse, is it a useful language feature to have MyNimName, mynimname, MY_NIM_NAME, My_Nim_Name, __MYNIM___name_ be different? When did you need this flexibility recently? Are we really so limited at naming things appropriately?
It's fine to make a big deal about something in theory but if it really was such a dumb idea it would have died over the decade Nim has been around. It was debated again prior to 1.0 and persisted, several good reasons are also mentioned in this thread. And it isn't even an original idea as brought up by several others.
If this is the reason someone doesn't try Nim then it's only unfortunate for them. Add this to the tabs vs. spaces, curlies vs. whitespace indentation or other so called concerns which make no difference in the grand scheme of things.
apiCall = __APICALL__
doneWell, unlike treeform, I like it to be:
api_call(system_call.inspect_something())
Which I find much more readable. What now?inb4 a Nim linter is written to force a consistent naming style throughout a codebase.
Already done:
https://github.com/FedericoCeratto/nimfmt
> Detect inconsistent variable/function naming
https://stackoverflow.com/questions/7375537/why-is-common-li...