Log in

No account? Create an account
Lindsey Kuper [entries|archive|friends|userinfo]
Lindsey Kuper

[ website | composition.al ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Shield your eyes. [Apr. 19th, 2008|05:54 pm]
Lindsey Kuper

Hey! It's been a few hours since I complained about Perl! Okay, so I've got an arrayref, let's call it $stuff:

my $stuff = [];

Except, oh, wait, actually it's an attribute of a class that's been implemented using that Class::Std thing, so it's initialized like

my %stuff : ATTR;
$stuff{ $id } = [];

So, actually, %stuff is secretly a hash, except, shh, you didn't hear me say that, we're not supposed to have to care about that. We just have this arrayref that we can get at (for this particular class instance) with $stuff{ ident $self }. (Or $self->get_stuff(), if you like, but I'll come back to that.)

This all came up because I came across this code I couldn't read:

foreach my $thing ( @{ $stuff{ ident $self } } ){

I stared at this for a while until I realized that the outer set of curly brackets around $stuff{ ident $self } weren't there as a hashref operator, but just as plain old block delimiters around the whole arrayref that was being dereferenced. Let's review: we've got curly brackets right next to each other, and they mean not only different things, but close to opposite things. It took me so long to puzzle out that I ended up showing it to Schwern to make sure I was thinking about it correctly. He said that I had it right, but added, "That part of dereferencing syntax is icky." If Schwern will admit to something being wrong with Perl, then that must really mean it's wrong!

What happens if we try to just write @$stuff{ ident $self }, without the delimiters? Apparently, the @ to the left makes the Perl parser try to chunk off "$stuff" by itself, and we get a compile-time error because Perl doesn't understand the symbol $stuff without its subscript attached.

So then I realized that, if we're good little "hey, look, my language can be object-oriented, too!" Perl programmers and we use a get_stuff() accessor instead of $stuff{ ident $self }, we can lose the inner set of curly brackets and make the whole thing a little nicer-looking and less ambiguous:

foreach my $thing ( @{ $self->get_stuff() } ){

And that's what I ended up doing in the real thing. (But notice that we still need the curlies delimiting the whole arrayref, and this time, if we try to leave them out and just write @$self->get_stuff(), we don't even get a compile-time error; we just get a run-time error telling us that something isn't an arrayref. Oh, yeah, and Class::Std doesn't make the get_stuff() accessor method for us by default; we have to tell it to do that.)

Using the accessor method seemed like one of those Vaguely Good Ideas anyway, and realizing that it would also make my code more readable was a Ray Of Hope. 'Cause, see, I believe that one way to tell if you're Making Good Choices is that seemingly unrelated little things keep working out in unexpected, good ways. Conversely, if seemingly unrelated little things keep going wrong, then you need to back up and figure out where your Bad Choice was. At least, I really want to believe that this is the way the world works.


[User Picture]From: jes5199
2008-04-20 05:30 am (UTC)
last year, I wrote Schwern an email about the related problem of:
push @{ $stuff{ident $self} } , @values;

and he wrote:
First thing you can do is stop comparing everything to Ruby ... Always whistfully looking
at Perl's younger sister will just damage the relationship.

but eventually he wrote this: http://use.perl.org/~schwern/journal/34526 as a response.

your code, autoboxed, could be fixed to
$self->get_stuff()->foreach( sub {
  my $thing = $_;
} )

which looks good if you totally hate the @{}

anyway. the reference vs data problem is a strange perl artifact. (okay, it exists in C++, but that's close to the metal, and I expect it). In ruby and python and javascript, everything is a reference, and that seems to work. php is worse than perl, having no references but a sort of nightmarish =& operator, which assigns-by-reference instead of copying. in Haskell, nothing is mutable, so the distinction is moot.
(Reply) (Thread)
[User Picture]From: jes5199
2008-04-20 05:37 am (UTC)
oh! and Perl-Best-Practices says you should use wantarray to decide if get_stuff returns a real array or an arrayref. or Contextual::Return.

such that both
foreach( $thing->get_stuff() ){ ... }
$arrayRef = $thing->get_stuff()
do the right thing.

Edited at 2008-04-20 05:39 am (UTC)
(Reply) (Parent) (Thread)
[User Picture]From: pixelherder
2008-04-20 08:51 am (UTC)
This is the sort of thing that eventually drove me to Python. I can has data structures?

Lua could also be added to the Ruby, Python, Javascript list.
(Reply) (Parent) (Thread)
[User Picture]From: lindseykuper
2008-04-22 02:02 am (UTC)
I know! That's what you said last time I complained about Perl!

I actually do believe that Perl can be beautiful, but I also believe that it fights you the whole way. At work, I think we're in too deep to switch to something else right now, so I need something other than work to motivate me to learn Python. I do have this XO laptop that I want to learn to develop for...
(Reply) (Parent) (Thread)
[User Picture]From: lindseykuper
2008-04-20 10:43 am (UTC)
Yeah, I remember reading that and wondering if it was about you! I heard your voice in it.

He mentioned autobox to me today, too, but then changed his mind and said that I should just write my own get_stuff(). I don't think I'm motivated enough to keep messing with it, but I should find out about the autobox thing, anyway.

Scheme is...well, it's mostly immutable, anyway. And becoming less so?

(Reply) (Parent) (Thread)
From: boojum
2008-04-20 06:37 pm (UTC)
I've found the C++ distinction between reference and data pretty straightforward to use in practice, but C++ makes much more use of typing in general than perl does. Perl has...five types? It doesn't seem worth bothering with types for that.
(Reply) (Parent) (Thread)
[User Picture]From: jes5199
2008-04-20 11:00 pm (UTC)
it's true, perl5 objects aren't part of this type system -- they're always references. so it only matters for primitives: array, hash, scalar, code, and glob. yeah, five.

the thing that bugs me about C++ is the dot vs arrow notation. Is there ever a place where it's ambiguous which one is correct? Couldn't a pre-processor pick which one you need? (okay, five minutes of research shows me a counterexample, but, yipes!)
(Reply) (Parent) (Thread)
[User Picture]From: stereotype441
2008-04-20 06:39 am (UTC)
At least, I really want to believe that this is the way the world works.

A few things are true if and only if you believe in them. This, I believe, is one of those things. Therefore it is.
(Reply) (Thread)
[User Picture]From: conform
2008-04-20 05:16 pm (UTC)
I can't imagine anyone really claiming that that syntax isn't at least a little ugly. You could debate how much it impacts the usability of the language, but it's clearly ugly. On the other hand, it has the modest virtue of more or less forcing inexperienced coders to confront the fact that they may not have a clear picture of the difference between a reference and a value (a virtue in a language that draws that distinction, anyway, which is, again, a debatable asset).

But the thought that springs into my mind is that you could also clean it up somewhat by simply taking an extra line to spell it out:

my $stuff = $self->get_stuff();
foreach my $thing ( @$stuff ) { ... }

The argument that you shouldn't have to jump through hoops to achieve clarity (though you still have that dereferencing "@") is, at one level, reasonable, but misses a deeper point, which is that coding for clarity is just flat out a Good Idea. Every language that I've ever used has a variety of ways to obfuscate itself. Perl has more than most (though the worst offenders are, thankfully, dinosaurs). Learning when to be verbose (for clarity) and when to be terse (D.R.Y.) is one of those lessons that many coders struggle with. Or worse, don't struggle with.

The interesting modulator in all of this is language culture, which inflects what is and what isn't "clear". Almost every language has idioms (again, perl may well have more) which to the outside observer are counterintuitive, noncommunicative, but for a coder operating in a given environment (a particular company, as a frequenter of perlmonks, whatever), those expressions can be eminently reasonable. You just have to be careful when you take those idioms with you somewhere else.
(Reply) (Thread)
[User Picture]From: lindseykuper
2008-04-22 01:49 am (UTC)
you could also clean it up somewhat by simply taking an extra line to spell it out

Totally. That's probably saner than what I actually did, which was to write the hairier code and then leave a long-winded comment about what it was doing. I guess I hope to educate someone (and myself).
(Reply) (Parent) (Thread)
From: boojum
2008-04-20 06:32 pm (UTC)
I believe that one way to tell if you're Making Good Choices is that seemingly unrelated little things keep working out in unexpected, good ways. Conversely, if seemingly unrelated little things keep going wrong, then you need to back up and figure out where your Bad Choice was.</em>


I think of this as one of the deep truths of language design, of architecture, of UI design, etc. etc. etc.
(Reply) (Thread)
[User Picture]From: pmb
2008-04-20 07:29 pm (UTC)

I rate that advice

/.: (Score: 5, insightful)

(Reply) (Parent) (Thread)
[User Picture]From: lindseykuper
2008-04-21 05:42 pm (UTC)

Re: I rate that advice

Thanks, Peter and Kim. It's good to get independent confirmation from smart people like you.
(Reply) (Parent) (Thread)