for fruit in fruits:
assert fruit is not 'apple'
print(fruit)
assert 'banana' not in fruits
etc. Especially in Python, it makes code flow very much like English.Edit: It also goes with the "don't put the type in the name" point, which I agree with in most cases. Depending on your use case, it most likely won't matter if fruits is a list, tuple, set, generator, whatever. The plural implies an iterable interface. However, if the type does matter, I will often use it in the name (in a dynamic lang like Python).
This is also useful when you have two types of collections in the same place, such as an array and dictionary.
for fruit in fruit:
print(fruit)
My brain is screaming at me right now that the above doesn't make sense. Even with a click glance, it sticks out like a sore thumb. I'm not entirely sure why, but I'd guess it's because it mimics natural language more, so my eyes are more used to parsing that for mistakes?`movie_collection` vs `movie_collections` is a bit trickier
> It also goes with the "don't put the type in the name" point, which I agree with in most cases.
Is that a problem in practice in Python? That's the whole reason Perl uses different sigils to denote different types of variables, which Python specifically rejected. Personally I prefer being able to tell if something is a collection, and which core type of collection, at a glance (barring refs).
That actually does allow the same name to be used as a scalar, an array and a hash, but it's considered very bad practice.
# Valid perl, but will get you nasty looks from coworkers
my @fruit = qw( apple banana banana apple apple mango apple mango banana );
my %fruit;
for my $fruit ( @fruit ) {
$fruit{$fruit}++; # increment %fruit hash item $fruit
}> I prefer being able to tell if something is a collection, and which core type of collection, at a glance (barring refs).
Not really a problem, but if you're writing more than a one-off script, such as a module you plan on sharing, it may be common that you get a mixture of concrete types coming in depending on the app and platform. I think in practice, it's actually beneficial to assume you do not know the core type of collection (if your operations will work with many/all of them).
For example, a range object or generator in Python 3, but a list in Python 2. And then someone else comes along and uses your modules with sets.
So with "fruits" (or something like "fruit_iter" for anyone who disagrees with plural naming), you know that you can safely iterate through it. But you may not be able to do random access, or reassignment of elements. There might be times when this matters, in which case you'd want to enforce a specific type.
The only thing I do not like about this is that in Python strings are also iterables. So the difference between passing "Apple" and ["apple"] can be quite large, and yet your program will iterate through "a", "p", "p", "l", "e" with no complaints. The worst experience I've had with this was working with a web API that would return either an array of strings, or only a string if there was one result (not a 1-element array), or a dictionary of objects if there were many results. 99% percent of the time it returned the array of string, and since strings and dictionaries are iterable, it took me a while to notice the bug.
I ought to learn Perl, because that's pretty cool. You're right that that example is terrible to read, haha, but I'm sure there are scenarios where it's helpful.
This touches on a big pet peeve of mine, and coincides with some ranting I was doing on the Scala Native post the other day. :)
Languages that support coercion should try to make sure they don't overload core operators for different types of operations for different core types. E.g. '+' for numerical addition and string concatenation (one is commutative, the other is not, and if you decide on which action to take depending the order of variables, that's confusing), or ==/!= for string equivalence and numerical equivalence (10.0 and 10 are numerically equivalent, but for strings we generally want an exact match).
Having an iterating operation work on a string without any preparation is one of those things that seems simple and useful, but likely causes a lot of confusion in dynamic languages in practice because you lose track of exactly what it's possible a variable can hold because it's often dependent on the return value of someone else's function. I imagine exposing a method on strings that returned an iterable interface, and requiring that be the method you iterate over a string, would reduce that confusion quite a bit.
> I ought to learn Perl, because that's pretty cool.
I think it's worth picking up the core concepts for anyone, because there's a few concepts (e.g. context) it implements as core parts of the language that are still rarely used elsewhere. Unfortunately, its hybrid beginnings mean that you can largely miss the importance of things like context early on because the code looks enough like what you are used to that you assume it works the exact same way, and 95% of the time that's true. The other 5% will leave you scratching your head and wonder why Perl seems so stupid or inconsistent, when really your mental model is wrong. List and scalar context and how they apply to the core types should be the first learning item on a new Perl programmer's list if they know another C-like language.
Are you sure? I could have sworn that I'd seen this as actual style advice in the Camel book. A trip through `perldoc perlvar` (http://perldoc.perl.org/perlvar.html) shows that, at the very least, Perl itself doesn't abide by this convention; for example, we have the scalar `$ARGV`, the list `@ARGV`, and the filehandle `ARGV`.
Sigils allow you to separate variables into different namespaces. It's
possible–though confusing–to declare multiple variables of the same name
with different types:
my ($bad_name, @bad_name, %bad_name);
Though Perl won't get confused, people reading this code will.
There are plenty of things that are shown as possible in the Perl docs, and only slightly less things recognized as generally a bad idea in most circumstances. Instead of Python's one way to do it, there's really more 1 to 3 accepted, idiomatic ways to do it, and another 2-3 that are considered "situationally acceptable" (those odd cases where it actually makes things more readable, etc). There's often a couple ways that are deemed generally just a bad idea, or at a minimum, still waiting for that special case where they can shine. ;)1: http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf (But you should buy it if you are interested, chromatic knows what he's talking about).
Notice, though, that I'm not talking about the Perl docs merely noting that it's possible—I agree that the spirit of the docs is more "look what I can do!" than "look what you should do." I'm talking about what Perl itself does (with the use of `$ARGV`, `@ARGV`, and `ARGV`—although maybe `$_` and `@_` is a better illustration).
chromatic is an excellent programmer, and I certainly respect his voice on Perl over, say, mine, but I feel that he is rather strict, and I do not take his opinions as necessarily representing those of the larger Perl community, as exemplified, among many others, by Wall, tchrist, Conway, and/or merlin.
I suspect that's a combination of Perl's influence from awk (@ARGV), wanting something easier than awk's ARGIND for the current index in ARGV, and wanting to try out some of these new features Perl had in the beginning. I also suspect that things like this may be on the list of things Larry regrets about early Perl choices. I believe he's on record as saying he regrets the choice of sigil variance for array/hash and array/hash access (@foo as $foo[0] instead of something like @foo[0]). He's got good reasoning for why he chose what he did (based on language, it makes sense), but it's just overly confusing for beginners.
> although maybe `$_` and `@_` is a better illustration
I'm willing to give them a special case, because they are unique, as variables go (well, less so than they should be given Perl's many magic variables, but I think you understand my point). That said, I don't think many Perl programmers would argue that @_ was a better choice than @ARGUMENTS, or something equivalent.
As for assuming the docs in general reflect the current best practices.. I'll just note that the perlopentut man page still uses bare filehandles in the majority of its examples, and to my mind that was decided long ago as a community to be downplayed in favor of lexical filehandles (but for more practical reasons than what we are discussing, bare filehandles are globally scoped).
> chromatic is an excellent programmer, and I certainly respect his voice on Perl over, say, mine, but I feel that he is rather strict
I'm not going to argue with that. I respect chromatic's opinions on style and Perl 5, but I'm not entirely sure he's capable of being entirely objective with Perl 6 yet (which I can understand). He is rather adamant about what he believes are better approaches to a topic.
> I do not take his opinions as necessarily representing those of the larger Perl community, as exemplified, among many others, by Wall, tchrist, Conway, and/or merlin.
Fair enough, but I wasn't sourcing that believe from Modern Perl, just pointing to it as evidence. To be honest, I haven't read Modern Perl (but I've read a lot of chromatic's writing from his blog back in the day when he was writing it), I just assumed it might have something to back up my view, so looked in it. My view on variable naming here is perfectly capable of being more my own opinion that the community, and I was projecting. It's hard to know in Perl unless there's a discussion (and sometimes even after that), as what's acceptable is often a mostly overlapping set of best practices from person to person, but rarely are the sets of preferences entirely equivalent. :)
That said, Conway's Perl Best Practices suggests "Name arrays in the plural and hashes in the singular." It doesn't address our topic directly, but I don't know where my copy went (I sourced that from one of the many two page reference PDFs for PBP) and I don't recall the reasoning he used for that one. I wouldn't fault you for disagreeing with him though, I've shifted my view on some of his suggestions over the year towards or away from his suggestions (notably not using parens on built-ins, but I'm more in-line with his thinking now than I was a decade ago).
* it's a book for novice programmers, people with perhaps six months of practical programming experience
* it's a book for novice Perl programmers, people who don't have voluminous experience with the language itself
I believe programming is an exercise in making tradeoffs based on incomplete information. You can't teach the kind of good judgment that's based on experience, but I can try, at least, to guide novices away from some of the traps that they're likely to fall into. The subtleties of separate namespaces are difficult enough to learn on your own that it seemed worthwhile to advise strongly against name cognates.
I don't expect that Larry, Tom, Damian, or Randal follow my advice. I don't even follow it in my own code many times. It's not advice for experts.
I always enjoy your writings on Perl, even if I sometimes disagree with specific opinion-based recommendations (as is, almost by definition, the prerogative of Perl programmers), and I hope that I didn't seem to be knocking you or them. I was not even disagreeing with this particular advice, just saying that it didn't necessarily establish the attitude of the broader Perl community on punning in variable names. (There always will be code golfers who will value cleverness over maintainability—and there should be; without them we would never have such gems as `[$a => $b]->[$b <= $a]` for `min($a, $b)`.)
In addition you have some words that don't pluralize well such as fruit or Lexus.
In my opinion the more verbose and unique you can make your variable names the better, even if that means adding redundant words.
I like type systems when I play around with personal projects in well-typed languages