It's what my company's entire code base is written in. So every hour of every work day for the past 6 months.
>To me it looks really no uglier than any other mainstream language, and one could easily make the argument that any other mainstream language you care to name is uglier in some of its own ways.
It's no one thing, but a bunch of little things that compound on top of each other. Until you get something like this:
while (<>) { ($h{$_}++ == 1) && push (@outputarray, $_); };
Mostly though it's how it's used. It can technically do anything, so a lot of the times it is asked to do everything. Until one day you wake up to find you have hundreds of perl files, all tens of thousands of lines long, that all interconnect in an insane Object Oriented hierarchy soup stretching across every conceivable programming space - from database control to money processing to security to web site design.
Saying that I see absolutely nothing wrong with that perl code you are highlighting as being obtuse or ugly. Anyone who understands Perl should not have an issue with that line. It is clear and concise.
There are a variety of things that Perl programmers would consider idiomatic (depending, I would say, on the background of the Perl programmer). Using something like (foo && bar) in this manner is actually quite common in some Perl code bases (although, I suspect it is more commonly used where there are multiple conditions that are chained -- Damian Conway's "Perl Best Practices" book has some examples of those).
In the example given, I suspect the author of that code did it that way to reduce the length and put it on one line. I understand the desire for concise code, but if it were me, I would spread it out more to make it easier to read (mostly, I just wouldn't put it all on one line). I like having concise code also, but there is a fairly definite line that I try not to cross. If I have to work hard at all to keep track of the pieces, it's time to either add some more whitespace (horizontally or vertically, or sometimes both), change some of the constructs, or add some temporary variables to make the intent clear.
I am the person most likely to have to deal with the code a year later, so like many others, I try to not confuse my future self.
That's a business culture thing. If you set the expectation, that it's okay to do that, people might do that. If you set the expectation that it's not okay, people shouldn't.
The equivalent C and Python are likely just as ugly (given that the equivalent python might be using a far too complex range statement or put it on a single line using : and ;, which is possible...).
That said, as bad code goes, that's not really that bad. The only non-standard things are <> and $_, and if you don't know what those are, you really haven't done the minimum of learning about the language (<> might be somewhat exotic in that form depending on the codebase, but $_ is not something you can get way with not knowing about). In all, the major problem with it is that it's not commented and uses poor variable names, which is something every language needs to deal with. I would write it like so if I wanted it on a single line (but I would probably use 2-3 lines):
# Report each duplicated line once
my (%lineseen,@linedups); # This was required in yours too right? I assume you're using strict...
while (<>) { (++$lineseen{$_}==2) && push(@linedups, $_); };
But I would likely opt for the following if doing it myself: # Report duplicate lines once
my %lineseen;
my @linedups = grep { ++$lineseen{$_}==2 } (<>);
Assuming I was using <>, which I generally don't since File::Slurp is usually available and clearer.Some people will look at this as evidence that Perl should be relegated to one-liners, but I find immense usefulness in combining my more engineered aspects with one-liners, and providing myself with a "project evaluator". What I do is create a simple bash script which just calls perl and sets the library include path to the project lib, includes a few useful things to always have (Path::Tiny, Try::Tiny, Data::Dumper, etc), and passed the rest of the args to Perl. Using DBIx::Class for SQL manipulation and/or using complex API client libraries I've written combined with the abilities of perl to do things easily as a one-liner is amazing.
Still mostly fine so long as you know you're only dealing with 7-bit ASCII, IIRC, but Caveat Emptor.
It's easier to just say File::Slurp in mixed company so people immediately know what it is if they look it up, rather than them be confronted with a grab-bag of functions.
The specific example cited
while(<>){ $h{$_}++ && ... }
is quite understandable to anyone who has used Perl for more than a few weeks. Its a common pattern. Complaining about this, which is, for the uninitiated, looping over reading each line from STDIN until EOF, incrementing a hash variable indexed by each line, etc.
This is a very common pattern in perl. Draw your own conclusion as to whether complaining about idiomatic language from a "skilled practitioner" is something one should take without a grain or two of salt.
And of course, being Perl, there are many ... many ... ways to accomplish the same task. Leveraging CPAN modules. I'd leave discovering some of the as an exercise for the reader.
Who knew you could do that in a programming language? Not sure I would have ever thought to try.
I even love the above sample while loop, you can tell the person who posted it is good because they can't create too heinous an example. The <> and $_ provide what I think of as visual anchors that describe a path for the data to follow. Obviously some style minded author could do it better, but it's not bad. The real line noise is from the one-liners for systems tasks I think.
You should see C++ Templates! Even the idiomatic examples in cppreference.com will blow up your head and require multiple re-reads.
while (<>) { ($h{$_}++ == 1) && push (@outputarray, $_); };
Would be written as the following in Raku: my @output-array = lines.unique; my @output-array = lines(:!chomp).unique;
where the `:!chomp` is a named parameter representing a `False` value for the named parameter `chomp`. AKA, `chomp => False`.We use Perl::Critic [0] to deal with issues like that. It has enabled us to develop a very consistent style, and helps new devs adopt to it quite quickly.