Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?

Mithaldu posted:

:siren: You need to stop golfing your stuff so hard. :siren:

Hey everyone, pro tip! This one, right here!

Just because you can chain nested indices together doesn't mean you should!

code:
# look how awesome my codez are

$megatron->{$artilary}{$squad_leader}[$squad_rank]{$decepticon_$type} = 'Starscream';

Adbot
ADBOT LOVES YOU

Erasmus Darwin
Mar 6, 2001
I think Mithaldu's got the right idea with making it more readable. Regardless, for the sake of information, here's a working version of the original.

code:
#!/usr/bin/perl -w

@array_of_hashes_of_arrays = (
{ some_array => [ 2, 3, 4, 5 ] },
{ some_array => [ 8, 9, 10, 11 ] }
                              );

for ($i = 0; $i <= $#array_of_hashes_of_arrays; $i++) {
    for($j = 0; $j <= $#{$array_of_hashes_of_arrays[$i]{some_array}}; $j++){
        print $array_of_hashes_of_arrays[$i]{some_array}[$j], ' ';
    }
}

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
Readable version:
code:
#!/usr/bin/perl
# don't put -w on your hash bang, gives you weird warnings when modules like autodie and CGI::Carp clash a bit

use strict;
use warnings;

my @array_of_hashes_of_arrays = (
    { some_array => [ 2, 3,  4,  5 ] },
    { some_array => [ 8, 9, 10, 11 ] },
);

for my $hash_ref (@array_of_hashes_of_arrays) {
    my $array_ref = $hash_ref->{some_array};
    print "$_ " for @{ $array_ref };
}
Alternatively:
code:
#!/usr/bin/perl

use strict;
use warnings;

my @array_of_hashes_of_arrays = (
    { some_array => [ 2, 3,  4,  5 ] },
    { some_array => [ 8, 9, 10, 11 ] },
);

my @content_lines = map extract_contents( $_, 'some_array' ), @array_of_hashes_of_arrays;

print join( "\n", @content_lines );

sub extract_contents {
    my ($hash_ref, $hash_key) = @_;
    my $array_ref = $hash_ref->{$hash_key};
    return join( ' ', @{ $array_ref } );
}

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it

Mithaldu posted:

You need to stop golfing your stuff so hard. Try it like this.
code:
my @array_of_hashes_of_arrays;

for my $i ( 0 .. $#array_of_hashes_of_arrays ){
    
    my $hash_ref = $array_of_hashes_of_arrays[$i];
    
    my $some_array_ref = $hash_ref->{some_array};
    my $last_index_of_some_array = $#{ $some_array_ref };
    
    for my $j ( 0 .. $last_index_of_some_array ){
        print $some_array_ref->[$j];
    }
}
I am in fact dumb. This is how you do it right:

code:
my @array_of_hashes_of_arrays;

for my $hash_ref ( @array_of_hashes_of_arrays ){
    
    my $some_array_ref = $hash_ref->{some_array};
    
    for my $value ( @{ $some_array_ref } ){
        print $value;
    }
}
Same thing as above, but actually readable.

Wow I did that and it worked out great! I assume perl like references better than lots of stacked brackets? I'm not sure what you mean by golfing though.

Ok, so how about assigning hashes to array indices? Would that look something like:

code:
my $hash{label} = "label\n";
my $hash_ref = $hash;
my $array[0] = $hash_ref;
print $array[0]->{label};
?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Golfing. To code emphasizing the least amount of keystrokes. Usually results in lovely, unreadable code.

Captain Frigate posted:

Wow I did that and it worked out great! I assume perl like references better than lots of stacked brackets? I'm not sure what you mean by golfing though.

Ok, so how about assigning hashes to array indices? Would that look something like:

Yes, pretty much. But after the first index, you don't need subsequent arrows for dereferencing.

code:
# untested
# quote your keys goddammit
# can't do key assignment and declaration at the same time

my %hash;
$hash{"label"} = 'My gay label';

my %other_hash = (label => 'My gayer label');

my $hash_ref = \%hash;

my @array = $hash_ref;

print $array[0]{"label"};

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
Your mistake was simply that you didn't understand what $# does. It gives you the last index of the array that has the name that follows directly after those sigils. So if you do something like: $#array[$i] perl tries to do this: 5[$i] (if @array has 6 entries). Obviously 5 is not an array, so it fails.

If you do something like this: $array[$i]{array} then you get back a reference to an array. If you want to treat that like an array you have to dereference it and tell perl how you want to treat it, either as an array: @{ $array[$i]{array} } or that you want to extract the last index number: $#{ $array[$i]{array} }

Of course this looks like arse and is completely undebuggable without going insane, so you just don't do things like that and keep them simple.

code:
my $hash{label} = "label\n";
my $hash_ref = $hash;
my $array[0] = $hash_ref;
print $array[0]->{label};
This will not work, because you need to explicitly create a hash, array or a single scalar, can't do a mix. Also, dereferencing with arrow is only necessary if the first element you're working with is a reference.

Here's alternatives on how to do this:

code:
my %hash = ( label => "label\n" );
my $hash_ref = \%hash;
my @array = ( $hash_ref );
print $array[0]{label};
Now with references, note the different bracketing. Different type of brackets create different things.

code:
my $hash_ref = { label => "label\n" };
my $hash_ref2 = $hash_ref;
my $array = [ $hash_ref2 ];
print $array->[0]{label};

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

quote:

# quote your keys goddammit
What? Why. There's no point whatsoever in doing that as far as i am aware. All it does is create the need to type more things and clutter the visuals up more.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
You know what, I take back what I said about quoting keys. My misunderstanding. :geno:

I thought the default case was it as an expression. Turns out that hasn't been the case for some time. I got it backwards. I'm confusing it with functions that consume parenthesis.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
I have no idea why functions feed on parens, but at least it's good to know i'm not insane. :)

Fake-Edit: Do you mean flattening of lists?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
The canonical example of what I was referring to is:

code:
# "expected" output is 14, from 7 * 2

print (3 + 4) * 2; # prints just 7

# proper statement

print +(3 + 4) * 2; # prints 14

# which I confused with

$a{print}  = 'scalar';      # bareword -> scalar
$a{+print} = 'expression';  # force evaluation
print %a;

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Triple Tech posted:

code:
# "expected" output is 14, from 7 * 2

print (3 + 4) * 2; # prints just 7

# proper statement

print +(3 + 4) * 2; # prints 14
Oh, right. I'd forgotten about that. I tend to wrap all my poo poo in parens except for some builtins and print only ever gets one single scalar from me.

Triple Tech posted:

code:
$a{+print} = 'expression';  # force evaluation
Whoa. :2bong:

Captain Frigate
Apr 30, 2007

you cant have it, you dont have nuff teef to chew it
Ok, how about getting a reference to an array stored in a hash? I feel like it would work like this:

code:
%hash = (
     array => [0.0, 1.0, 2.0],
     );

my $hash_ref = \%hash;

my $array_ref = \@{ $hash_ref }{array};

print ${$array_ref}[1];

#or even

my $array_ref = \@hash{array};

print ${$array_ref}[1];
but neither of those work.

Those two tell me that I have the wrong kind of reference, and if I change the sigil to % I get a syntax error.

EDIT:

Triple Tech posted:

The canonical example of what I was referring to is:

code:
# "expected" output is 14, from 7 * 2

print (3 + 4) * 2; # prints just 7

# proper statement

print +(3 + 4) * 2; # prints 14

# which I confused with

$a{print}  = 'scalar';      # bareword -> scalar
$a{+print} = 'expression';  # force evaluation
print %a;

I have no idea what is happening here. What does the preceding "+" do?

Captain Frigate fucked around with this message at 21:01 on Jan 22, 2010

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Captain Frigate posted:

Ok, how about getting a reference to an array stored in a hash? I feel like it would work like this:

code:
%hash = (
     array => [0.0, 1.0, 2.0],
     );

my $hash_ref = \%hash;

my $array_ref = \@{ $hash_ref }{array};

print ${$array_ref}[1];

#or even

my $array_ref = \@hash{array};

print ${$array_ref}[1];
but neither of those work.

Those two tell me that I have the wrong kind of reference, and if I change the sigil to % I get a syntax error.

EDIT:


I have no idea what is happening here. What does the preceding "+" do?

array is an arrayref already because you used []. You can get it simply

http://codepad.org/ofB2C9R3

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Wow, way too much crazy going on up there. You have a fundamental misunderstanding with references and how to access them. Granted, I went through the exact same thing, but once you get it, it's pie (except for maybe some weird edge cases or trying to find the last index of an array ref, both of which could easily be addressed by not nesting indices).

Captain Frigate posted:

I have no idea what is happening here. What does the preceding "+" do?

The "unary plus" :airquote: operator forces Perl to evaluate the expression in a different manner. In the first example, it consumes the parenthesis before print can, so print evaluates over the whole expression instead of just the parenthesis. In the second example, you're saying that print should be treated as more than just a bareword, and that you want to plusify (aka do nothing to) the return value of a function called print.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Captain Frigate posted:

references ???
Do yourself a favor and stop guessing. Read this entire document: http://perldoc.perl.org/perlref.html

Play around with what it does, step by step. Then ask here for clarifications on things that are still unclear.

Erasmus Darwin
Mar 6, 2001

Captain Frigate posted:

Ok, how about getting a reference to an array stored in a hash?

One thing to keep in mind is that scalars are the only thing you can store inside arrays and hashes. So when you do this:

code:
%hash = (
     array => [0.0, 1.0, 2.0],
     );
what's happening is that you're creating an anonymous array containing 0.0, 1.0, and 2.0. A reference to that array (references are scalars) is then being stored in the element named 'array' within %hash. So the value of "$hash{array}" is actually an array reference which Perl would display as something like "ARRAY(0x814f9c8)" if you tried to print it directly.

(Technical sidenote: For simplicity, I skipped over a small intermediate step where the data being assigned to the hash is technically a list.)

Ulta
Oct 3, 2006

Snail on my head ready to go.
I'm using Perl for the first time. I'm coming from doing C# in MS Visual Studios 2008, and now all I have access to is xemacs. The transition is a little rough. I find I'm spending waaaay too much time tracking down where I forgot a ; or $. Is there an IDE out there that can do syntax highlighting and error checking?

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
It is a bit glitchy due to being a Firefox based ... thing, but Komodo IDE will give you a visual line debugger and syntax checking exactly like you're used to.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
xemacs should do syntax highlighting and some form of auto-indenting for you

Sabacc
Jul 8, 2002

Wasted two hours trying to figure this out. I give up.

I'm using Windows XP, Perl 5.x. On the command line, if I do this in a directory:

code:
dir
I get the following files:

code:
file1.xml
file2.xml
file3.xml
...
file 50.xml
Fine.

But when I try to opendir in Perl, I'm very clearly missing files, specific ones--about five of them.

I've tried:

* Running ATTR using Windows; all of the files have A set.
* These files exist in Perforce, so I've tried deleting locally and Force Synching. The same files are missing in Perl.
* Curiously, I did
code:
system "dir";
in Perl. The same five files were missing!
* In Perl, I tried
code:
@files = <*>;
print @files;
Still same missing files.
* In Perl,
code:
Win32::File::GetAttributes($f, $attrs);
Spat out a list of files that could be detected, with attribute of 8224. Of course, the missing files were missing

In all appearances there is no hidden attribute set on these absent files. I've also tried renaming the file (file2_2.xml)--still nothing. There is some MAGIC PROPERTY set on these files that I can't for the life of me detect. For the love of God HOW DO I MAKE THESE FILES ACCESSIBLE?

tl;dr: can see the files in Explorer; can see them using dir at the command line; cannot see them whatsoever in Perl.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
1. What's your exact Perl version

2. What are your results from doing
code:
use Path::Class;
for my $file (dir('/path/to/folder')->children) {
    print "$file\n";
}
(CPAN documentation for Path::Class is here

Sabacc
Jul 8, 2002

Otto Skorzeny posted:

1. What's your exact Perl version

2. What are your results from doing
code:
use Path::Class;
for my $file (dir('/path/to/folder')->children) {
    print "$file\n";
}
(CPAN documentation for Path::Class is here

1. 5.8.8 built for MSWin32-x86-multi-thread

2. Had to install Path::Class using ppm. Mother effer. Riddle me this:

* I'm using Cwd. When I did 'cwd()' for the path to folder, the files were missing
* When I used '.' (script is running in the same dir), the files were missing
* When I used an absolute path, e.g. 'C:/dev/dir/', the files were goddamn there.

Edit: just tested--absolute path with opendir shows the files, too

Explanation, anyone?

Sabacc fucked around with this message at 20:05 on Jan 27, 2010

Fenderbender
Oct 10, 2003

You have the right to remain silent.
Hurf durf Windows. :B

tef
May 30, 2004

-> some l-system crap ->

Sabacc posted:

Explanation, anyone?

Your working directory is not what you think it is? If the only way you can access the files is absolute and not relative, perhaps your script *isn't* running with the cwd you expect.

:confused:

Sabacc
Jul 8, 2002

tef posted:

Your working directory is not what you think it is? If the only way you can access the files is absolute and not relative, perhaps your script *isn't* running with the cwd you expect.

:confused:

In that same directory that I am opendir() into, I'm processing all the files. it just threw a "cannot open" file on one of the missing files I noted earlier.

God only knows, maybe there is some encoding corruption or something.

Edit: Forget it, appending an absolute path fixed this problem too. No encoding/XML errors that I can see. Who knoooooowsssss

Sabacc fucked around with this message at 00:51 on Jan 30, 2010

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
A wizard did it

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
speaking of magic, Moose::Util::TypeConstraints* is pretty neato-burrito, and brings some perl 6-ish features to 5:
code:
package Maus::Command;
use Moose;
use Moose::Util::TypeConstraints;

subtype 'IRC_Str'
    => as 'Str'
    => where { $_ !~ /1nj3ct|startkeylogger|\0|\x01/ }
    => message {"Can't say that on irc, sorry broseidon!"}
;

subtype 'CommandStr'
    => as 'IRC_Str'
    => where { /^\w+$/ }
    => message {"Commands can't have non-word chars, sorry bro!"}
;

...

has 'aliases' => (isa => 'ArrayRef[CommandStr]', is => 'ro', required => 0);
(I've been told the semicolon on its own line is weird, but I like to have an end demarcation to things that vertically aligns with the beginning)





*I've been informed that MooseX::Types is similar but 'higher tech' but haven't given it more than a cursory glance myself




e: added links

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
MooseX::Types is worth looking into, if you're creating your own types there's the possibility of collisions with other packages that define the same type, whereas MX::Types prefixes all custom types with the calling package, preventing this. It also exports the short version of those names into your class via a constant sub, meaning you don't have to quote your types:

code:
use MooseX::Types::Moose qw/ Str Int /;
use Business::CreditCard ();

use MooseX::Types -declare => [qw/
  CreditCardNumber LiberalInt
/];

use Sub::Exporter -setup => { exports => [ qw/ 
  CreditCardNumber LiberalInt
/] };

subtype LiberalInt,
  as Int,
  message { "Invalid number." };

coerce LiberalInt,
  from Str,
  via {
    (my $int = $_ ) =~ s/\D+//g;
    $int
  };

subtype CreditCardNumber,
  as Str,
  where { Business::CreditCard::cardtype($_) },
  message { "Invalid card number." };

# in an HTML::FormHandler class

has_field 'card_number' => (
  type     => 'Text',
  label    => 'Credit Card number',
  apply    => [ LiberalInt, CreditCardNumber ],
  required => 1,
);

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
    Someone on either #moose or #perl (don't remember which and too lazy to grepack my logs) built Perl 5.10.1 on OS X with clang, and it passed 1609 of 1611 regression tests. Didn't catch any word of performance, although I'm told clang's code gen is more or less on par with gcc 4.3 and a bit behind 4.4.

    Still, it impresses me that they're that close to compatibility with something as crufty as gcc (as horriffic as perl's internals are, gcc's are far, far worse. They use a somewhat bizarre mix of their own wrappers around malloc/free that iirc allocate from their own arena, their own custom garbage collector, and semi-automatic management via obstacks. I'm told it takes a reasonably skilled programmer about 6 months to get up to speed to the point they can work on the parser or codegen).

    Now, the Perl codebase is in C, which they've had more or less under down pat for a while (along with Objective-C for reasons you can guess), but as you've probably heard the clang folks are making strides in C++ too, just very recently advancing to the point that the compiler is self-hosting.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
          It must've been #perl because it wasn't #moose.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
for (('to you', 'dear '.shift)[0,0,1,0]) { print "Happy birthday $_! " }

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?

Otto Skorzeny posted:

for (('to you', 'dear '.shift)[0,0,1,0]) { print "Happy birthday $_! " }

Mind blown. Is it someone's birthday?

Edit:

code:
> perl -Mfeature=say - namegoeshere
say "Happy birthday $_!" for ('to you', 'dear '.shift)[0,0,1,0]

Triple Tech fucked around with this message at 21:48 on Feb 16, 2010

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Triple Tech posted:

code:
perl -Mfeature=say

Incidentally, you can enable all supported features by running with -E rather than -e :tmyk:

Nevergirls
Jul 4, 2004

It's not right living this way, not letting others know what's true and what's false.
Tatsuhiko Miyagawa is the best thing to happen to Perl in a decade. First, he wrote Plack. Then he found that CPAN.pm was swapping on his VPS, so he wrote cpanminus, which is tiny, does the right things with no configuration, and covers enough to almost entirely replace CPAN(PLUS).

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
So it doesn't seem to be widely documented and I suspect it's a bit of a dirty hack, but I've discovered a fairly easy to enable cross-schema joins with DBIx::Class and Catalyst - change your schema class's __PACKAGE__->table definition to use the fully qualified name:

code:
# DB::local::Schema::local_table
__PACKAGE__->table('local.local_table');

# DB::foreign::Schema::foreign_table
__PACKAGE__->table('foreign.foreign_table');
Append some lines to your DB/Schema.pm files to make another call to load_classes, specifying the foreign schemas you want to load:
code:
# DB::local::Schema
__PACKAGE__->load_classes('DB::foreign::Schema' => [qw/ foreign_table /]);
And add a relationship:
code:
# DB::local::Schema::local_table

__PACKAGE__->belongs_to(qw/
  foreign DB::foreign::Schema::foreign_table foreign_id
/);
This is enough to get it working under MySQL/Postgres (which we use in production), but SQLite, which we use on our local dev machines, is a little tricker. Since it operates on a single stand-alone file per DB, with no namespacing to speak of, you must resort to this dirty poo poo, using the ATTACH DATABASE command, which allows you to use the fully qualified schema.table syntax:
code:
# myapp_local.yml
Model::DB::local:
  connect_info:
    dsn:           'DBI:SQLite:__HOME__/db/local.db'
    on_connect_do: "ATTACH DATABASE '__HOME__/db/foreign.db' AS foreign"
Essentially you're attaching each SQLite database to every other database, which is all kinds of hosed up, but for us it's only in dev so it's no big deal.

frunksock
Feb 21, 2002

So I was golfing the other day and tried to get an array slice to the end of an anonymous array and realized I couldn't find any way to do it without somehow naming the array first.

E.g., neither of the following work:
code:
@foo = (a, b, c, d)[2..$#_]
@foo = (a, b, c, d)[2..-1]
Naming the array works with either method, of course, and indexing via $#_ or -1 work when used alone, without the range operator. Just curious if anyone knows why this is the case, or how to do it. I've got some hazy guesses on why, no clue on how to do it without naming the array.

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
How's this?
code:
$ (qw/zero one two three/)[-2 .. -1]     
                                                           
$ARRAY1 = [
  'two',
  'three'
];

frunksock
Feb 21, 2002

Mario Incandenza posted:

How's this?
code:
$ (qw/zero one two three/)[-2 .. -1]     
                                                           
$ARRAY1 = [
  'two',
  'three'
];
That's interesting. It still doesn't solve the problem, though, since it still requires you to know the length of the array if you want the slice from n to the end. I simplified the example I used -- in the actual code I was working with, the anonymous array was a function return value of unknown length.

EDIT: I know something like (@bar[0..2], @foo) = split; works too -- I was just surprised that the range syntax doesn't work.

frunksock fucked around with this message at 17:36 on Mar 8, 2010

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?
Thought that might be the case. In that case, try assigning to undef, it looks weird but should work in recent versions of Perl (a quick Googling didn't tell me which version made it syntactically valid):
code:
my (undef, undef, @foo) = get_foo();
Edit: Looks like the second and third editions of the Camel book both have this listed so it should work all the way back to 5.6 or so.

Mario Incandenza fucked around with this message at 19:15 on Mar 8, 2010

Adbot
ADBOT LOVES YOU

Bob Morales
Aug 18, 2006


Just wear the fucking mask, Bob

I don't care how many people I probably infected with COVID-19 while refusing to wear a mask, my comfort is far more important than the health and safety of everyone around me!

Why does
code:
print "$$";
Give me the following result:
code:
22324

  • Locked thread