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
Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?

yaoi prophet posted:

Just an obscure word of warning (since this somewhat unlikely to crop up for most people) but man did it ruin my day once: "list context" can crop up when you aren't always thinking about it, and due to perl flattening lists when you're not looking this can have interesting results.

[...]

So, just be careful with wantarray.
Agreed. In my opinion, contexts in Perl are too implicit to modify the behaviour of a function - a more explicit method should be used (like parameters). To be honest I can't really see any reasonable use for wantarray().

Update: Actually, I can see how checking for void context would be useful. List-vs-scalar is still too messy though.

Mario Incandenza fucked around with this message at 08:38 on Aug 27, 2008

Adbot
ADBOT LOVES YOU

npe
Oct 15, 2004

Fenderbender posted:

You're placing an empty array as a value, so it's compiled as essentially just nothing, and so it offsets all the key/value pairs in the hash.

Sure, we know why it happens, but the point is that it's a gotcha that can cause problems due to the sneaky ways that list context will suddenly appear without you realizing it.

I consider it a gotcha because wantarray is precisely the sort of thing that is tempting to use when you need to retroactively modify an existing function that is already in use. "Man, I'd really like to have an array here instead of a string. Hey, I can just have that function check wantarray, and no one will ever know!" That's when everything breaks, because that function is being used in parameterized argument lists all over the place.

Well, that's how it happened to me, anyways. The moral of the story is: either don't use wantarray at all, or if you do, it's probably best to not retroactively add it to an existing sub unless you feel really good about your unit test coverage.

Fenderbender
Oct 10, 2003

You have the right to remain silent.

yaoi prophet posted:

Sure, we know why it happens, but the point is that it's a gotcha that can cause problems due to the sneaky ways that list context will suddenly appear without you realizing it.

I consider it a gotcha because wantarray is precisely the sort of thing that is tempting to use when you need to retroactively modify an existing function that is already in use. "Man, I'd really like to have an array here instead of a string. Hey, I can just have that function check wantarray, and no one will ever know!" That's when everything breaks, because that function is being used in parameterized argument lists all over the place.

Well, that's how it happened to me, anyways. The moral of the story is: either don't use wantarray at all, or if you do, it's probably best to not retroactively add it to an existing sub unless you feel really good about your unit test coverage.

Now that I'm awake to compound more on this, there was an interesting issue that arose recently at my work which this list flattening is used for in a legitimate sense.

When trying to match "john", "jon", "johnathan", or "jonathan" from an array of first names using map (yes, I know grep is much more suited, but bear with me), the code my coworker was having issue with was something along the lines of

@names = qw(john jacob jeremy jon johnathan allan jonathan);
@names = map { /^joh?n/ } @names;


would return

['john', undef, undef, 'jon', 'johnathan', undef, 'jonathan']

Now, that's because you're returning a false/undefined value since the regex wouldn't match. What instead you needed to do was to use

@names = map { /^joh?n/ ? $_ : () } @names;

This will use that "sneaky" behaviour of lists to create:

['john', 'jon', 'johnathan', 'jonathan']

This was when I started to realize the usefulness of this behaviour. Thought it might be an interesting enough of an anecdote since it seemed relevant enough even if it's going over something glaringly obvious to most people.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
While in general you're certainly right (map { ... ? ... : () } is useful), in this case your code can be written as:

code:
@names = grep { /^joh?n/ } @names;

Fenderbender
Oct 10, 2003

You have the right to remain silent.

Sartak posted:

While in general you're certainly right (map { ... ? ... : () } is useful), in this case your code can be written as:

code:
@names = grep { /^joh?n/ } @names;

Fenderbender posted:

(yes, I know grep is much more suited, but bear with me)

heeen
May 14, 2005

CAT NEVER STOPS

SpeedFrog posted:

To be honest I can't really see any reasonable use for wantarray().
I've seen this:
code:
sub getStuff()
{
my @foo;
.
.
.
return wantarray? @foo : \@foo;
}
how about :

return generateHugeListOf10_000_000elements() if wantarray;
return $numberof10_000_000elements;

heeen fucked around with this message at 18:57 on Aug 27, 2008

leedo
Nov 28, 2000

heeen posted:

I've seen this:
code:
sub getStuff()
{
my @foo;
.
.
.
return wantarray? @foo : \@foo;
}

This is essentially what I'm doing, though I'm tempted to just always return the array.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Could someone please explain what a lexical $_ is used for and how to use it?

perldoc

Subotai
Jan 24, 2004

Triple Tech posted:

Could someone please explain what a lexical $_ is used for and how to use it?

perldoc

It is used the same way you would use the global version. It just means that you can now change $_ in a certain scope and not affect the global version.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Blegh, I was going to ask for a working example but I think I finally figured it out (in my head...) :pseudo:

Edit: Boo, no, I'm confused.

code:
# does not work
sub asdf { print $a };

my $a = 'boost';
asdf()

#-- works
my $a = 'boost';
sub asdf { print $a };

asdf()

#-- ugh... works
my $a = sub { /boost/ };
{
  local $_ = 'boost';
  print 2 if $a->()
}

Triple Tech fucked around with this message at 16:53 on Aug 28, 2008

ashgromnies
Jun 19, 2004

Triple Tech posted:

Blegh, I was going to ask for a working example but I think I finally figured it out (in my head...) :pseudo:

Edit: Boo, no, I'm confused.

code:
# does not work
sub asdf { print $a };

my $a = 'boost';
asdf()

#-- works
my $a = 'boost';
sub asdf { print $a };

asdf()

#-- ugh... works
my $a = sub { /boost/ };
{
  local $_ = 'boost';
  print 2 if $a->()
}

Which version of Perl has the lexical $_? My version doesn't.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
^^ 5.10

Is the following a legitimate use of symoblic references? Or are they like a universal evil?

code:
my $testing = do { ... };
my $database = 'Company::Database::' . ($testing ? 'Smoke' : 'Domain');

eval { require $database };
{
  no strict 'refs';
  our $dbh = ${"${database}::dbh"};
}
My objective is to have a module consume this handle without knowing where it comes from. Also, without manually typing out an if-else branch.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
I'd say that's acceptable. Symbolic references are forbidden by use strict because it's so easy to screw up in subtle ways with them, if they're allowed everywhere. In your case, the symbolic reference very obvious and deliberate, so it's okay.

As a comment on your design, each $dbh should be replaced by a dbh method. Globals are a universal evil. :v:

Mario Incandenza
Aug 24, 2000

Tell me, small fry, have you ever heard of the golden Triumph Forks?

heeen posted:

code:
sub getStuff()
{
my @foo;
.
.
.
return wantarray? @foo : \@foo;
}
Yes, I'm saying it's cleaner to always return an arrayref and deref it yourself if needed, so that you don't get bitten by list flattening with assigning to a hash. @$arrayref isn't that big a deal.
code:
return generateHugeListOf10_000_000elements() if wantarray;
return $numberof10_000_000elements;
If you're returning a 10 million element list as an actual list you have greater problems than wantarray.

Triple Tech posted:

My objective is to have a module consume this handle without knowing where it comes from. Also, without manually typing out an if-else branch.
I don't think it's a valid use. As Sartak recommended, make a dbh method, and that way if you pass in a full class name you don't need symbolic references, as Perl's OO system will happily accept strings.
code:
my $class = "Company::Database::Smoke";
my $dbh = $class->dbh;

# or even
my $method = "get_dbh";
my $dbh2 = $class->$method;

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Hmm, I'm sort of in a bind. Using that way, the subroutine is called as a method and the class is the first argument. What if in the package I'm calling it's a class subroutine (no self/class) and not a method?

code:
# works
$class->realMethod; # method style

# does not work
$class::realSubroutine; # interpreted as scalar that doesn't exist

syphon^2
Sep 22, 2004
Is this the best way to sort hashrefs alphabetically (well, ASCI-betically)? Something seems inefficient about it, but it's how I've been doing it so far.
code:
#!perl

use strict;

my $data = GetData(); #GetData returns a hashref packed full of information.
my @alphabetical_list = sort keys %$data; #a sorted list of keys

#Use the array to iterate through the hashref alphabetically.
foreach my $key (@alphabetical_list) {
    print $data->{$key) . "\n";
}

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

syphon^2 posted:

Is this the best way to sort hashrefs alphabetically (well, ASCI-betically)?

Yes.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
What about it seems inefficient? I'd say you could combine that array value into the list that the for loop uses, maybe that cuts away the cost of creating an array.

Also, maybe your outer process could be improved some, or could be sort-agnostic.

syphon^2
Sep 22, 2004
I don't know, it seemed that creating a new array and sorting it JUST for the sake of iterating through another hash in a certain manner (alphabetized) wasn't the best way to do things. I had no valid reasons to think so, I just wanted to make sure. :)

Fenderbender
Oct 10, 2003

You have the right to remain silent.

syphon^2 posted:

I don't know, it seemed that creating a new array and sorting it JUST for the sake of iterating through another hash in a certain manner (alphabetized) wasn't the best way to do things. I had no valid reasons to think so, I just wanted to make sure. :)

Well, as Tech said, you don't need to create a new array, just use

foreach my $key (sort keys %$data) {

CanSpice
Jan 12, 2002

GO CANUCKS GO

Triple Tech posted:

Hmm, I'm sort of in a bind. Using that way, the subroutine is called as a method and the class is the first argument. What if in the package I'm calling it's a class subroutine (no self/class) and not a method?

code:
# works
$class->realMethod; # method style

# does not work
$class::realSubroutine; # interpreted as scalar that doesn't exist
What about :
code:
&{$class}::realSubroutine;
?

Ninja Rope
Oct 22, 2005

Wee.

Triple Tech posted:

Hmm, I'm sort of in a bind. Using that way, the subroutine is called as a method and the class is the first argument. What if in the package I'm calling it's a class subroutine (no self/class) and not a method?

code:
# works
$class->realMethod; # method style

# does not work
$class::realSubroutine; # interpreted as scalar that doesn't exist

I find it a lot easier to use separate modules and objects for this kind of thing, and then use standard OO techniques. That is, I'll instantiate a Database::Testing or Database::Production object based on whether I'm running a test or in production, and each will implement the same interface. You don't need to use symbolic references when you can just pass the actual object.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Let's say you make a really simple class (it never stays that way does it :)). Do you bother implementing getters for private use or do you just access the object's innards directly? That is, should you be allowed to know how you work? Or should the same amount of care and abstraction be taken as if it was publicly consumed?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Never.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
I was asked out of band for clarification. :angel:

I never use direct hash access (outside of accessors of course). This was true even before I started using Moose for every class.

Subotai
Jan 24, 2004

Triple Tech posted:

Let's say you make a really simple class (it never stays that way does it :)). Do you bother implementing getters for private use or do you just access the object's innards directly? That is, should you be allowed to know how you work? Or should the same amount of care and abstraction be taken as if it was publicly consumed?

There is no need to try and abstract the internal data members of a class from itself.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Subotai posted:

There is no need to try and abstract the internal data members of a class from itself.

Your class will get more complicated. Having layers of abstraction will ease that evolution.

Subotai
Jan 24, 2004

Sartak posted:

Your class will get more complicated. Having layers of abstraction will ease that evolution.


I for one find it much more of a pain in the rear end to have to write a function to access a data member in a class that I already have access to. Unless you really think you might have to go back and redo how or the information in the class is stored or handled, and it is too much work to actually change the hash in the places you use it, then go ahead and write an accessor function. I believe it mainly will be a waste of time, involve extra code that doesn't need to be there, and make the code harder to debug.

He is talking about a simple class in Perl. It shouldn't be something you turn into a monolithic piece of code. He probably shouldn't have any use for accssesor functions internally.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
You're both correct. For really simple classes, it's too much of a pain to make accessors. But, more often than not, contrary to people's initial assessments, small projects evolve into complicated ones. So sartak is also right, early accessors help isolate implementation details from the model, in case they need to be changed.

Ever since I learned that objects in Perl are just suped up versions of primitives, I've tried to shoehorn using an array (anonymous scalar!) in place of something that usually ends up evolving into a hash. Rarely ever (never?) is the object I'm working on an attribute-less collection of things (i.e. a real array).

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Subotai posted:

I for one find it much more of a pain in the rear end to have to write a function to access a data member in a class that I already have access to.

If you're writing all of your accessors, yeah I can see how it would be too annoying to do regularly. I just do has foo => (is => 'rw'); of course..

Use Moose, Class::Accessor::Fast, Class::Accessor::Complex, Object::Tiny, I don't care! It is too much of a pain to define new and every accessor for every class.

Subotai posted:

Unless you really think you might have to go back and redo how or the information in the class is stored or handled, and it is too much work to actually change the hash in the places you use it, then go ahead and write an accessor function. I believe it mainly will be a waste of time, involve extra code that doesn't need to be there, and make the code harder to debug.

The key here is to work with Perl's strengths.

$self->accssesor is an error.

$self->{accssesor} is a bitch to debug.

Subotai posted:

He is talking about a simple class in Perl. It shouldn't be something you turn into a monolithic piece of code. He probably shouldn't have any use for accssesor functions internally.

It's a balancing act. The more complex your class becomes, the more you'll want the encapsulation. For me, the tipping point is when I bless.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
So I had this question about staining a list of elements with an index... And it turned into a discussion about for vs map and what not. (I wanted to avoid using a for loop)

Why are we allowed to assume that the map of a list is done in order? Like you know how the perldoc says we can't assume hash keys have a predictable order? Also, by preventing users from making this assumption, couldn't we run maps on multiple processors? Like, Perl scripts can transparently gain the benefits of multi-core every single time they use map/grep.

Wasn't there something in Perl6 for this already? Or am I making this up?

code:
my @a = 1 .. 100;
my $i = 1;
print join "\n", map { $i++; "$_ - $i" } @a;
Edit: Currently browsing Perl monks. I think what I'm talking about is referred to as a "serial map" vs a "parallelizable map". Perl5's is serial :( but what will Perl6's be? Or will it have two explicit types of maps? Or will it optimize away a side effect free one somehow?

Edit2: Oh man, so many little questions... Do you write side effectish maps? Is it bad style? Is it okay to use assignment in a map? How about a for loop?

Triple Tech fucked around with this message at 17:51 on Sep 5, 2008

Erasmus Darwin
Mar 6, 2001

Triple Tech posted:

Why are we allowed to assume that the map of a list is done in order? Like you know how the perldoc says we can't assume hash keys have a predictable order?

Having a fixed order is an integral concept to the list type, so it makes sense to preserve that order when working with the type. Hashes don't have a fixed order for their elements, so attempting to impose one on the output of the keys function would often result in extra work.

So I guess it sort of boils down to it's that way because that's the way it is. Still, you need to keep in mind that these are two of the fundamental data building blocks of the language. Their differences complement each other and allow you to create more complex data structures.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
You misunderstand (probably because I write poorly). I'm not talking about the return order. Of course the return order has to be ordered. I'm talking about the execution order of the map. Two different things.

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

Triple Tech posted:

You misunderstand (probably because I write poorly). I'm not talking about the return order. Of course the return order has to be ordered. I'm talking about the execution order of the map. Two different things.

Generalizing map to run in parallel in Perl is a bad idea, because for a large proportion of maps the synchronization and communication overhead for even two worker threads would dwarf the runtime of the serial map. In any case, you're generally better off with something like futures and a worker pool than you would be trying to make list primitives heuristically parallelize various parts of your code, and that can be easily achieved in a Perl5 module.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
Little performance question:

This runs in 5 seconds:
code:
use constant ONE => 1;
use constant ZERO => 0;
use constant TWO => 2;

my $a;

my @test = (4,2,3);
 
for (0..10000000) {
    $test[ONE]++;
    $test[ZERO]++;
    $test[TWO]++;
    $test[ONE]--;
    $test[ZERO]--;
    $test[TWO]--;
    $a = $test[ONE];
    $a = $test[ZERO];
    $a = $test[TWO];
}

This runs in 14 seconds:
code:
my $a;
  
my %test = (
            ONE =>4,
            ZERO => 2,
            TWO => 3
           );
 
for (0..10000000) {
    $test{ONE}++;
    $test{ZERO}++;
    $test{TWO}++;
    $test{ONE}--;
    $test{ZERO}--;
    $test{TWO}--;
    $a = $test{ONE};
    $a = $test{ZERO};
    $a = $test{TWO};
}
Is that normal or am i overlooking something?

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
Stab in the dark. A hash lookup is more expensive than an array lookup.

In C land, all the elements in the array would be right next to each other. But for a hash, first you'd have to consult a hash index of all the keys, then see where the key points, then look it up.

Subotai
Jan 24, 2004

Mithaldu posted:

Little performance question:

This runs in 5 seconds:
code:
use constant ONE => 1;
use constant ZERO => 0;
use constant TWO => 2;

my $a;

my @test = (4,2,3);
 
for (0..10000000) {
    $test[ONE]++;
    $test[ZERO]++;
    $test[TWO]++;
    $test[ONE]--;
    $test[ZERO]--;
    $test[TWO]--;
    $a = $test[ONE];
    $a = $test[ZERO];
    $a = $test[TWO];
}

This runs in 14 seconds:
code:
my $a;
  
my %test = (
            ONE =>4,
            ZERO => 2,
            TWO => 3
           );
 
for (0..10000000) {
    $test{ONE}++;
    $test{ZERO}++;
    $test{TWO}++;
    $test{ONE}--;
    $test{ZERO}--;
    $test{TWO}--;
    $a = $test{ONE};
    $a = $test{ZERO};
    $a = $test{TWO};
}
Is that normal or am i overlooking something?


Both are O(1) but the hash will have more overhead since it has to do some extra math to find the hash bucket.

TiMBuS
Sep 25, 2007

LOL WUT?

Triple Tech posted:

Edit: Currently browsing Perl monks. I think what I'm talking about is referred to as a "serial map" vs a "parallelizable map". Perl5's is serial :( but what will Perl6's be? Or will it have two explicit types of maps? Or will it optimize away a side effect free one somehow?

Well for Perl 5 it made more sense to have a serial map because for starters Perl is imperative, and secondly back when Perl 5 came out multi-core processors and vector extensions didn't really exist for the common man.. So it would be kinda odd to iterate a list passed to map in some seemingly random order on a single processor.

Perl 6 has (should have) both serial and parallel maps (and loops). By default they work in serial, but if you want paralleled code what you are meant to do is 'junction' all of the values in your list together using 'all' and perform an operation on the junction object.

A parallel map would probably be something along the lines of @newarray = map { 2*$_ }, all(@array); or maybe even just @newarray = all(@array)*2 although, I don't know if/how the second one would work.
e: on second thought perhaps it would be better invoked as @newarray = all(@array).map{2*$_}; ?

Triple Tech posted:

Edit2: Oh man, so many little questions... Do you write side effectish maps? Is it bad style? Is it okay to use assignment in a map? How about a for loop?
I do write maps with side effects but not often.
It's bad style if you look at it from a functional perspective but perl isn't functional.
Assignment in a map? Uh.. I guess so.
A for loop in a map? That'd be fun to try to read (save it for one-liners).

TiMBuS fucked around with this message at 13:35 on Sep 7, 2008

uG
Apr 23, 2003

by Ralp
How can I install the Moose branch of Catalyst 5.80 using cpan? :(

Adbot
ADBOT LOVES YOU

leedo
Nov 28, 2000

uG posted:

How can I install the Moose branch of Catalyst 5.80 using cpan? :(

I don't think that is possible. You would probably have to do an svn checkout and install that way. I don't really see the point in doing that, I can't imagine much is changing on the userspace end of things.

edit: speaking of which, there was a good interview with mst about Catamoose today
http://jjnapiorkowski.vox.com/library/post/catamoose-part-two-mst-speaks.html

leedo fucked around with this message at 21:25 on Sep 8, 2008

  • Locked thread