but with a warning: "Using a hash as a reference is deprecated." What would the undeprecated form be? I can make it work without the warning using the code flagged with workaround, but I don't see why I should have to create an extra reference if I can avoid it.

The code at problem 2 produces a flat-out error: "Can't use string ("grannysmith") as a HASH ref while "strict refs" in use at test.pl line xx". What it should do (what I want it to do) is print "Found red delicious key". What am I doing wrong?

Er, also, for problem 2, $fruit will be a string for each iteration of the loop, since 'keys' will return a string for each key of the hash ---- yet you're treating it like it'll be a hash reference.

I'm not sure what you're trying to do but I'm assuming you're trying to iterate within the keys of the hash-within-the-hash (within the apples hash) and am trying to find whether or not 'reddelicious' exists?

print "$_\n" for keys %{%h->{apples}}; # Warning: Using a hash as a reference is deprecated.

Classic new person mistake :) See the "%h" I put in italics? You want "$h" instead. Reason: the signul -- @, %, $, or sometimes * -- in front determines what type of data you want out of the evaluation of the expression. You want the scalar value out, so you need to use $. Consider these examples:

Think for a minute about what $fruit is. It's your hash key, which is a scalar string. It makes no sense to dereference a scalar string as a hash, which is exactly what the error told you. It's the same as writing "reddelicious"->{reddelicious}. I don't know what you're trying to do with this bit of code. If you want to see if there exists 'reddelicious" key in 'apples', then this suffices:

if (exists $h{'apples'}->{'reddelicious'}) { ... }

Note the indirection operator on the SECOND part. That's because your first part is a HASH, which contains a HASH REFERENCE. If you want to find what fruit has a key 'reddelicious', then you do this:

You need to check with ref() the type of data in each key since your hash %h mixes scalars and hash references.posted by sbutler at 12:12 AM on March 27, 2009

References sound scary in Perl, but they get much easier to work with the more you use them with indirection arrow operations. A lot less guesswork and cleaner code.posted by Blazecock Pileon at 12:15 AM on March 27, 2009

Let me say just a couple more things about perl variables that may help you here.

What is the output? Better question is, how does perl tell the difference between $foo, @foo, and %foo in those print statements?!?

The answer is not the signul out front! Noticed I used the same one for all three prints because in all three cases I wanted a scalar out of the expression. The way perl knows the difference is by how the variable is used!

It knows the first $foo evaluates to 1234 because it is just plain.

It knows the second $foo[ 0 ] evaluates to 'bar' because it has array index brackets after it.

It knows the third $foo{ 'three' } evaluates to 3 because it has the hash key lookup braces after it.

#2: There is no way to express an immediate hash in perl. What do I mean by immediate? I mean an expression that all by itself, ignoring constants, evaluates to a hash. Your basic types are:

No hashes! You might be tempted to say that list #3 is a hash, but it's not. It's just a fancy way of writing exactly the same list #4. That is, '=>' in perl is almost exactly like ',' (except it always interprets its left hand side as a string, even when not quoted).

But again, those are all scalars. They just happen to be references to data of another type. And when you have a scalar that is a reference, that's when the indirection operator comes in, or sometimes you have two signuls together:

Meanwhile here's a diff that solves your problem for you. I suggest that you read perldoc perlreftut a couple of times as you're still confused about perl references. Also the book Perl Best Practices is brilliant for working out the right way to deal with references. I can tell that you're still confused rather than badly informed because it took me ages (5-10 minutes) to work out what you'd done wrong.

Also good to see you're using perl. Stick with it, it reaps rewards (and for object orientated stuff, ignore all other advice and use Moose;)

also you should indent properly. Perl Best Practices is worth looking at for advice here too.posted by singingfish at 1:31 AM on March 27, 2009

I'm a bit thick when it comes to data structures, so whenever I have trouble identifying structures, I just use Data::Dumper::Simple and Dumper the recalcitrant structure to stdout. Enlightenment follows (usually).posted by scruss at 3:00 AM on March 27, 2009 [1 favorite]

First, if all you're trying to do is print this out, use Data::Dumper or a related module.

The larger problem seems to be that you're dealing with a data structure that mixes string scalars and references to hashes, and you're not sure how to deal with it. I do this often, and provided an example here.

Personaly I like the debugger for working out where I am in a data strucutre, hence why I had $DB:single=1 (force a breakpoint running under perl -d) in my diff. You can use "x $data" to get a nice readable dump of the data structure.posted by singingfish at 2:51 PM on March 27, 2009

Gah! It was all so obvious (in retrospect).

I'm coming back to perl after a long hiatus in which I've been working with ksh and sql scripts, so I'm rusty -- and I was never never much more than a perl beginner to start with.

I posted this question on a Friday afternoon after I'd spent most of the day wrestling with an issue I thought I understood. I'd re-read perlretut and flipped back and forth through the camel book to no avail. I'd searched perlmonks but couldn't seem to fix on the answer.

In the end I was doing the stupidest thing possible - randomly swapping around sigils, braces, and indirection operators in a half-assed attempt at making something happen. What was lacking was a clearer understanding, and I your answers have assisted greatly. Also it's Monday, and I've had coffee.

For those interested, I'm writing a script that builds special types of script for our BI server and then executes them - under Windows. It reads in a config file (using Config::General) to determine what needs to be executed (and when, and how), and then builds the script and runs it at the appointed interval or after the nominated event occurs.

It's a biggish project that goes a bit beyond what I currently know of perl (as you've already seen), but I figure the best way to learn something new is to bite off more than I can chew and then chew as fast as possible.

I've already used Data::Dumper to make sure that my config file loads up properly and everything is where I thought it would be. Config::General parses your config file into a hash (not a hashref). The internal structure of the hash depends entirely on what was in your config, but in my case contains ordinary scalar values, references to hashes, and references to arrays.

Someone referenced Perl Best Practices - I have read parts of that book, and usually my code is fairly cleanly laid out (to my eyes at least). I just didn't know how to get the indenting working within the <code> tag in my post. When I was at Monash I snuck into a few of Damian Conway's lectures. He's quite an amazing guy.

Thanks again to everyone who replied. You are a pack of magnificent bastards.posted by Ritchie at 4:33 PM on March 29, 2009

« Older Where can I find the names of ... | You have Crohn's disease. You... Newer »

Tags

Share

About Ask MetaFilter

Ask MetaFilter is a question and answer site that covers nearly any question on earth, where members help each other solve problems. Ask MetaFilter is where thousands of life's little questions are answered.