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
Ninja Rope
Oct 22, 2005

Wee.
You can look at %INC to figure out which modules are in use.

Adbot
ADBOT LOVES YOU

Ninja Rope
Oct 22, 2005

Wee.
How's this?

code:
#!/usr/local/bin/perl

use warnings;
use strict;

package a;

sub a {
 die "@_";
}

package main;

sub {
 my $package = 'a';
 my $function = 'a';
 @_ = ( 'welcome', 'to', 'a::a!' );
 goto \&{"${package}::$function"};
}->();

Ninja Rope
Oct 22, 2005

Wee.

mister_gosh posted:

I have a question. I have a filehandle I'm printing to:

code:
open(OUT, ">C:/example.txt");
...
print OUT "something";
...
close OUT
If someone CTRL-C's this script, nothing gets put in to C:/example.txt. Is there a way to ensure it closes properly or a better way of doing this?

Edit: thinking about this some more, is there a way to do something like if a user does CTRL-C or if there is an abrupt end or big error, can the program say "on exit, close this file handle?"

All file handles are always closed when your program exits. Are you sure that something else isn't going on when users ctrl+c out of the program?

Edit: A language reaches perfection when there is nothing left to take away, not when there is nothing left to add (similar to RFC1925). For that reason I'm a little worried about Perl6...

Ninja Rope fucked around with this message at 01:44 on Dec 9, 2007

Ninja Rope
Oct 22, 2005

Wee.

Satan's Scallion posted:

This is true but he wants the buffer flushed to the file first, which does not happen if you ctrl-c (at least on the systems I have available to me to experiment with).

I was under the impression that dirty write buffers are flushed when the handle is closed, but I don't really care enough to double check that. If we're sure that's what's happening, then you're right and the signal handler is the best way to go. However, I'd probably wrap the code that works on OUT inside a lexical block and use local $SIG{INT} = sub( close(OUT); exit; }.

Also, it's best to use actual variables to hold your file handles (eg, open($fh, 'file') instead of open(FH, 'file')).

Ninja Rope
Oct 22, 2005

Wee.
That's pretty strange, I wonder if that has to do with how SIGINT is handled by default. Maybe Perl doesn't change the default SIGINT handler so when SIGINT is received Perl doesn't get a chance to flush its buffers, and the data never made it from Perl into the OS's buffers. But when you throw the exit into the signal handler, Perl does its whole shutdown routine as normal?

Anyway, you're right that if you need to insure some kind of behavior on SIGINT, a signal handler is the way to go. The only defined default behavior for SIGINT is to exit and anything outside of that should be explicitly added by the programmer.

I was actually mentioning the file handle thing more for mister_gosh (or anyone else using old bareword style handles). Since we're correcting one part of his program, we might as well correct everything about it. :)

Ninja Rope
Oct 22, 2005

Wee.

Triple Tech posted:

I don't understand what you're trying to say with this. By your logic, a stream of ones and zeros is perfect, because there's nothing left to take away. But that doesn't mean it's good for programming. Similarly, just because Perl 5 is pretty good on its own now doesn't mean it is immune from things to which it is insufficient in the future, like multi-methods and concurrency.

I think there has to be a balance, and I prefer when it leans more towards simplicity (that is, fewer builtins but a language flexible enough that 'advanced' features can be added by modules) than "kitchen sink", which Perl5 definitely seems to be now. However, it seems like some things are being added gratuitously to Perl5 (and 6), like the "say" function. We've already got print and $\, and printf, and they're adding another builtin to do something similar?

This is just an example, of course, but in my opinion (that of someone who does not design languages, merely uses them), it's just another function to remember and another reserved word. Yes, it might be a few characters shorter to say 'say "hi"' versus 'print "hi\n"', but is that really worth it?

Don't misunderstand, Perl5 is one of my favourite languages to use, but adding more features isn't always an improvement. For instance, in my mind, the removal of the "magic variables" ($|, $/, etc) would do a lot more to improve the language than adding more.

Ninja Rope
Oct 22, 2005

Wee.
code:
# winnah
say for @items;

# sad panda
print "$_\n" for @items;
I really do think that's needless. We have $\ specifically so you don't need 'say':
code:
local $\ = "\n";
print for @items;
Yes, that is still more characters to type, but this avoids creating a new builtin for every possible output record separator string.

Triple Tech posted:

And then verbosity gets into how people think in terms of chunks and lines of code, despite what language they're in... Terseness rules, Perl wins.

I disagree, maintainability and clarity rule (though that may be more an artifact of how I work and not indicative of the majority of Perl programmers). Adding more builtins increases terseness and clarity at the cost of a more complex language (and runtime, and parser) and smaller namespace. At a point you have to draw the line when to stop adding things, and I think say() was a good place to have drawn it. Builtins/keywords that help with multithreading/IPC are definitely welcome, though.

Edit: Agreeing with tef.

Ninja Rope fucked around with this message at 06:42 on Dec 9, 2007

Ninja Rope
Oct 22, 2005

Wee.
We could guess better if you posted some code.

Ninja Rope
Oct 22, 2005

Wee.
It's also generally preferable to use real scalars for file handles (open($fh, '<', '/etc/password');) as opposed to the all-caps style handles (but that wouldn't make a difference for what you're doing).

Ninja Rope
Oct 22, 2005

Wee.
It's also useful when you want to make sure the parser knows you want to reference a function, like when using constants as hash keys:

code:
use constant FRY    => 'Captain Yesterday';
use constant BENDER => 'Super King';
use constant LEELA  => 'Clobberella';

my %themesong = (
 'Captain Yesterday' => 'is fast',
 'Super King' => 'is the best one of the three',
 'Clobberella', => 'beats you up',
);

# This won't do what you want
printf("%s %s!\n", FRY, $themesong{FRY});
# This works
printf("%s %s!\n", LEELA, $themesong{&LEELA});
# This does too
printf("%s %s!\n", BENDER, $themesong{BENDER()});
There are, of course, other ways.

Ninja Rope
Oct 22, 2005

Wee.

LightI3ulb posted:

Does anyone know of any modules that would allow me to receive mail and work with the attachments? The ones I've found on google are typically just for sending.

search.cpan.org is a much better resource for finding modules than any other search engine.

If you search there for "pop3", there are a bunch of modules returned. I've used Mail::POP3 client before and it worked alright. I ended up using one of the MIME modules to decode and process attachments, but I don't remember what or how I did it. I'm sure there are similar modules for IMAP.

Ninja Rope
Oct 22, 2005

Wee.

ShoulderDaemon posted:

You are aware that if you do @foo = $bar =~ m/(abc)def(ghi)/ then you get @foo = ('abc', 'ghi'), right? That would let you do this with array indexes instead of soft references.

This is a good solution. You could define constants and access your resulting array with them similar to how POE works (eg, $blah=$matched[MATCHED_NAME]). You can also do ( $match1, $match2 ) = $bar =~ m/(abc)def(ghi)/ to directly set the variables (just like anything else that returns an array), or even ( $hash{blah}, $hash{blah2} ) = $bar =~ m/(abc)def(ghi)/ if you really want to use a hash.

Ninja Rope
Oct 22, 2005

Wee.

NotShadowStar posted:

So I inherited this Perl program where the designer has done everything possible wrong, including obscure syntax rules and complicated global data structures that all sub-functions modify directly. I'm rewriting it to make things sane for me, but I can't decipher some of it. For instance, can someone help me unwind these kinds of variables into english or less code noise?

${$$g_mapTransform{$frame}}[0]
${$$xaPlate[$iRow][$iCol]}{'gt'}

Also, what.
return (@g_errors == 0);

As for how to rewrite those to be more "clear", I would rewrite this: "${$$g_mapTransform{$frame}}[0]" as this: "$g_mapTransform->{$frame}->[0]" and "${$$xaPlate[$iRow][$iCol]}{'gt'}" as "$xaPlate->[$iRow]->[$iCol]->{'gt'}".

Ninja Rope
Oct 22, 2005

Wee.

Triple Tech posted:

After the first deref, you don't need subsequent derefers.

$a->{lookup}->[lookup] == $a->{lookup}[lookup]

Sure, they might not be necessary, but I like keeping them, stylistically. I try to keep everything consistent, so if I use -> for dereferencing in one place I should use it everywhere in a particular file or project. Also, I remember old versions of ActivePerl didn't like hash references more than two or three levels deep, unless you used arrows, so that's how I got in the habit. Still, you're right, it's just a matter of preference.

Ninja Rope
Oct 22, 2005

Wee.
Look at Parse::RecDescent on CPAN.

Ninja Rope
Oct 22, 2005

Wee.
You should be able to enumerate all of the keys for a given registry entry just like a hash, something like:
code:
my %copy;
foreach my $key ( keys(%{$Registry->{"//$server/LMachine/SOFTWARE/KEYNAME"}) ) {
 $copy{$key} = $Registry->{"//$server/LMachine/SOFTWARE/KEYNAME"}->{$key};
}
It's just like copying any other hash key by key. You might even be able to say:
code:
my %copy = %{$Registry->{"//$server/LMachine/SOFTWARE/KEYNAME"});
That's what I gather from reading the documents, anyway.

Ninja Rope
Oct 22, 2005

Wee.
A couple of comments:

code:
my @word_list = ();
This is unnecessary. While assigning "" to scalars does have an effect (they default to "undef"), arrays are already initialized as empty arrays. It doesn't appear that your program is relying on your scalars to be initialized to empty strings, so you can probably remove that too.

code:
&readConfigFile($configFile);
&readSubDir($logDirectory);
Using ampersands on function calls is outdated. Just call them with readConfFile($configFile);.

code:
sub readConfigFile
{
	open(CONFIG, $_[0]) || die("Unable to find config file");
It's bad practice to use the 2-parameter form of open() this way. If $_[0] contains something like ">/etc/passwd", your program will overwrite /etc/passwd. Obviously that's not much of a concern here, but it's good to get into the habit of doing it the safe way. Try open(CONFIG, '<', $_[0]);.

Additionally, all-caps filehandles are outdated (but still useful). Unless you've got a really good reason to use one, it's probably better to use a simple scalar variable. Something like my $config_fh; open($config_fh, $_[0]).

In general, you should assign local names to all parameters in a sub, sort of like this:

code:
sub thing {
 my ( $config_file_name, $generic_parameter_1, @other_junk ) = @_;
 # Now use $config_file_name and such here, instead of $_[0].
}
This is mainly just for clarity, but it also makes life easier when you end up changing the sub's parameters. If you end up changing anything in @_ inside a sub, it will change the variables passed into the function (as if all elements of @_ were secretly references to the original data), so be careful when using @_ directly.

code:
	my $setting = '';
Again, no need to initialize to an empty string here.

code:
		#once you're in the config, get all the lines in that config
		for($setting)
		{
			/LogFilesDirectory/ && do
			{
				$logDirectory = $configLine;
				chomp($logDirectory);
			};
			/Output/ && do
			{
				$outputDirectory = $configLine;
				chomp($outputDirectory);
			};
			/WordList/ && do
			{
				push(@word_list, $configLine);
			};
		}
Stylistically I don't care for this at all. I think it's very obtuse and confusing to developers to see for used this way, and it would be clearer to simply match against $setting directly. This is valid perl and I'm sure it works fine, I just dislike the paradigm because I believe it's not intuitive.

While it is valid here, I really dislike using the implicit $_ whenever possible. There are side effects to using $_ in loops that may crop up if you're not aware of them, but mostly it is much clearer, I believe, to use the foreach my $var (@stuff) form, which puts the loop variable data in $var, like you did above. I would also suggest changing /WordList/ && do to a regular if statement.

Finally, I greatly dislike the use of do {} in this context (or as error handling for failed function calls, like open(...) or do { die; }. I perfer a simple if statement. Again, technically valid, but I think it can be non-intuitive. A lot of the developers I work with disagree.
code:
			if($fileName =~ /^.*\.log$/)
The construct ^.* is unnecessary here. This regular expression would be better written as /\.log$/. The "match anything at the beginning" part is implied. As a rule of thumb, any time you use .* you should think twice because it is rarely necessary and correct.

I hope this doesn't seem to strict, but I've found that the above corrections help make programs that are easier to maintain over time.

Ninja Rope
Oct 22, 2005

Wee.

MrHyde posted:

What's the difference between the all-caps filehandles and just using a scalar variable?

People above covered it well, and it's also discussed in Conway's "Perl Best Practices", which I thought was released for free but I can't seem to find a copy of it. Basically it comes down to scoping and code clarity issues, and I think it's a lot more intuitive to use a scalar like everything else. There's also IO::Handle.

quote:

So are you saying instead of the open(...) or do { die; } (it's what I use in PHP so I just intuitively used it here) I should just put the open statement inside an if? Would I just put the {die;} portion of the code inside an else then?

Yeah. Just use an if statement if there are multiple lines needed to handle your open() (or other function) failures. I'd write it like this:
code:
if ( !open($fh, '<', $var) ) {
 # Error handling code goes here.
}
If you just want to die (or run any other simple statement), this is okay too:
code:
open($fh, '<', $var) || die "Can't open file: $!";
Which is similar to what you have already. I meant the advice for your regular expression matching code (which uses do {}), but I was also trying to point out that I have seen it elsewhere used to handle failures in open. Sorry if I was unclear.

quote:

Nah, I'm trying to learn so this is great feedback. I'm picking most of the stuff I'm doing up off websites and whatnot (haven't gotten around to picking up a book) so I'm sure some of it may be ill advised or outdated. The comments are much appreciated.

Any time. Conway's "Perl Best Practices" is a good book to follow. I think some of what he says is unnecessary, but I would say I agree with 95% of it and it's one of the best books for learning the right way to do things in Perl. In general, I try and use code that looks similar to how it would be written in C while still using standard Perl-isms where I can.

Edit:

Triple Tech posted:

code:
{
  open my($fh), 'foo.txt' or die;
  process($fh);
}

# $fh is already closed and dead! :)

This is fine, but I don't think it's really necessary. I'd rather see the explicit close() simply for consistency and in the case things get changed around later and $fh is forgotten about. However, this code is more interesting because you used open() without parentheses along with an or statement.

This works fine, but changing that or to a || completely changes the meaning of the program, despite the fact or and || apparently do the same thing. In reality, though, || binds tighter than or, so while or applies to the whole open statement, || applies only to the closest value, which in this case is 'foo.txt'. Since 'foo.txt' (a non zero-length string) is always true, code using open without parentheses and || would never die on error, since the || is testing 'foo.txt' instead of the return value from open. In this case, or will work with or without parentheses, but || will not.

(I'm not pointing this out because I think you don't know it, Triple Tech, I was pointing it out for anyone else who might not. Also, this is why I always use parentheses around open, and prefer its placement inside an if block.)

Ninja Rope fucked around with this message at 06:59 on Jul 11, 2008

Ninja Rope
Oct 22, 2005

Wee.

genericadmin posted:

Right, I thought someone above was saying that using the two-arg form with no mode was bad because it could clobber an existing file.

Also... does anyone in this thread do much XS?

That was me. I was saying that using the two-arg form of open is unsafe when the second argument is under the user's control. Obviously if the second argument is properly cleaned, or not under the user's control, then it is not an issue, but it never hurts to be more explicit and use the three-argument form.

I've done some XS but I wouldn't say I'm an expert. The last XS I did was creating a Perl wrapper around the HP Open View API. It worked out pretty well, considering.

Ninja Rope
Oct 22, 2005

Wee.
To expand on what Triple Tech wrote...

xobofni posted:

1. Can someone tell me what $response->authority actually is? Printed as string, it looks like Net::DNS::RR::A=HASH(0x9060438) Net::DNS::RR::A=HASH(0x90604a4)... which doesn't seem to be an Array or reference to one.

The authority method returns an array of Net::DNS::RR objects, and you are correctly accessing the first element with [0]. I think you're confused because of how you printed out the return value from authority, since printing out the contents of an array prints out each of its elements as a string without directly telling you that you printed an array.

xobofni posted:

2. And why does the syntax I'm using the reference the elements in the array work (just using parentheses instead of something like @{})?

That syntax is used for array references. You're working with an array here, not an array reference, so that syntax is not needed.

xobofni posted:

3. In line with the previous questions, what are the alternative ways to get the scalar value of it (instead of using int())?

You don't need to use int there, the if should work fine without it. In general, if you want the length of an array, you should use the scalar function. Using int forces the returned array into scalar context (which is the array's length), and the converts it to an integer (which it already is). Using int does the same thing as using scalar but with an extra layer of indirection (and confusion).

Ninja Rope
Oct 22, 2005

Wee.
This is a perfect time to do something like:
code:
local $/ = ' '; # Change the input record separator to a single space while we
                # read our area code file, since the area codes are space-
                # delimited and not newline-delimited.
You can then use <> as before.

(Although, if performance was an issue, it would be better to read from the file 4 bytes at a time (3 for the area code + 1 for the trailing space) and chop the result. Let the OS handle the prefetching by specifying the correct flags to sysopen.)

Ninja Rope
Oct 22, 2005

Wee.

uG posted:

code:
   my @resource_loop;

   foreach(@trade_nations) {
            my $resource_hash = $self->dbh->selectrow_hashref("SELECT * FROM nation_info WHERE id = ?", undef, $_);

            push(@resource_loop, %resource_hash);
   }

   return \@resource_loop;
}

Does this code run under use strict? Where is %resource_hash defined? Are you sure you don't mean to push $resource_hash instead?

Ninja Rope
Oct 22, 2005

Wee.
Add use warnings; right before use strict; or you're fired. Out of a cannon. Into the sun.

Ninja Rope
Oct 22, 2005

Wee.
How does using Moose affect performance (eg, run speed, memory usage)?

Ninja Rope
Oct 22, 2005

Wee.

checkeredshawn posted:

code:
foreach my $arrayref (@blocks) {
  &getstuff($arrayref, \%config);
} 

It's also worth noting that using the ampersand (&) prefix on subroutines is generally not used any more.

Edit:

checkeredshawn posted:

Hmm, I tried $config->{$alias} = $field and I get this error:

Use of uninitialized value in hash element at config.pl line 47.

This error implies that $alias is undefined.

Ninja Rope
Oct 22, 2005

Wee.

checkeredshawn posted:

Ah, thanks for the ampersand tip, I was unsure about that also. The undefined value error message confuses me because I definitely declare it in the first block of code with

code:
my ($field, $alias, $fieldstring, $aliasstring);

An "undefined" variable does not mean it was not created with "my", it means it contains the value "undef" (similar to NULL value in a database). If you didn't declare the variable with "my" you would get a "Global symbol "$asdf" requires explicit package name" error.

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.

Ninja Rope
Oct 22, 2005

Wee.
'last' will exit a while/for/foreach/etc loop, like 'break'. 'continue' is 'next' in perl, though perl does have a continue statement, it just works differently than you'd expect. Finally perl also has a 'redo', which restarts the loop without evaluating the conditional again.

perldoc -f (last|first|redo|continue) has all of the details.

Ninja Rope
Oct 22, 2005

Wee.

TiMBuS posted:

ee: OR use Html::Template in your css code and use tmpl_if to set the color in there. That would be far less ugly.

I think you had it right the second time. Have HTML::Template change the class that the div is a part of, don't have it change the CSS. Ideally your CSS should be specified in a separate file and cached by the client's browser so it doesn't need to be re-sent for each request.

Ninja Rope
Oct 22, 2005

Wee.

CanSpice posted:

code:
open my $outfh, "outfile.whatever";
print $outfh "$fields{$to_print}\,";

You should also use parentheses around the open command (or any command that takes multiple parameters and returns something), to help avoid writing code like this:
code:
open my $h, '<', 'file' || die "Failed to open file!";

Ninja Rope
Oct 22, 2005

Wee.

syphon^2 posted:

Any advice would be greatly appreciated.

I've used Net::LDAP many times to interact with Active Directory and it has worked quite well. Where exactly are things failing?

Ninja Rope
Oct 22, 2005

Wee.
I don't see why one would be any faster than the other, the big delays will still be network latency and the efficiency of whatever network protocol the remote registry service uses.

Ninja Rope
Oct 22, 2005

Wee.

SpeedFrog posted:

It's possible, though only under Linux/Unix. According to this Perlmonks thread, Windows will exhibit the blocking you describe, so you must use a two-socket solution.

That thread is 5 years old. I haven't tried it, but I would be surprised if you can't send and receive from the same socket on Windows. You sure can using winsock/BSD sockets.

Jawn, if it hangs on the recv() call then there's no data there to be received and it will block until there is some. If that's not what you want, you've got a few options, but your best bet is to use select() (or IO::Select) to test whether there is data waiting on the socket before calling recv(). If you have two sockets bound to the same interface and port, there is no guarantee which socket will receive the data, and it could be that the socket that received the data isn't the socket that you called recv() on.

Ninja Rope
Oct 22, 2005

Wee.

JawnV6 posted:

I'm working on ubuntu 8.04. "Hang" was a terrible word, it's not picking up the data. On my network tracer I'm seeing the computer send out a ICMP Port Unreachable to the other code's UDP request, this doesn't happen if I just have the code do a recv() immediately. I think it has something to do with the Broadcast flag, I send out Broadcast then recv() non-Broadcast data, I don't think the same socket can do this? I'm going to try closing the socket (if that's a real thing) and initializing a listener for non-broadcast on the local port.

I don't want to talk out my rear end without testing it, but I'm pretty sure that's not necessary. I've got some broadcast socket code somewhere I'll try and dig up later today and let you know how I got that working.

Ninja Rope
Oct 22, 2005

Wee.

Ninja Rope posted:

I don't want to talk out my rear end without testing it, but I'm pretty sure that's not necessary. I've got some broadcast socket code somewhere I'll try and dig up later today and let you know how I got that working.

Okay, so I see what's going on here. When you create the broadcast socket with a remote address of 255.255.255.255, it will only send data to and receive data sent from that address, as if it were a connected socket. In your case, you should create the socket without specifying a remote address, and then specify the destination address as a packed sockaddr in your call to send(). Like this:

code:
$socket = IO::Socket::INET->new(
    LocalPort => $local_port,
    Proto     => 'udp',
    Broadcast => 1,
) or die "Socket failed: $!";
$broadcast_sockaddr = pack_sockaddr_in( $local_port, inet_aton( '255.255.255.255' ) );
$socket->send( $message, 0, $broadcast_sockaddr ) or die $!;
Note, you might receive the same broadcast packet you just sent, so be ready to filter that out of necessary.

Ninja Rope
Oct 22, 2005

Wee.

JawnV6 posted:

Ah! That makes sense, thanks. When I get home I'll screw around with it some more, thanks for the help!

If you get stuck again on this let me know. I've got some code I use that does exactly this, but I'd rather not post it here.

Ninja Rope
Oct 22, 2005

Wee.

JawnV6 posted:

I ended up closing and re-opening, it's working fine from watching it on wireshark. Thanks.

Doesn't this introduce a timing issue, though? You can't guarantee how fast you can close and reopen the socket, or even that you can at all, if the OS runs out of sockets or your process out of FDs.

Ninja Rope
Oct 22, 2005

Wee.

Fenderbender posted:

I typed this.

I went with:
code:
print "It's a seven character palendrome!\n" if $string =~ /^(.)(.)(.).\3\2\1$/;
So, did you get the job?

Ninja Rope
Oct 22, 2005

Wee.
Modules need to return a "true" value to indicate they loaded successfully. However, since the main body of code in a module isn't inside a function, you can't actually use a "return" statement, you need to place a statement at the end of the module that implicitly returns a true value.

In short, add
code:
1;
to the bottom of WorkerNode.pm.

Adbot
ADBOT LOVES YOU

Ninja Rope
Oct 22, 2005

Wee.
ToolSet might be helpful for this.

  • Locked thread