Perl-Sensitive Sunglasses | |
PerlMonks |
Modifying a parameter to a recursive functionby CoDeReBeL (Initiate) |
on Apr 08, 2009 at 20:19 UTC ( [id://756451]=perlquestion: print w/replies, xml ) | Need Help?? |
CoDeReBeL has asked for the wisdom of the Perl Monks concerning the following question: Hi!I'm having trouble with the following code. It contains a subroutine that calls itself recursively. It modifies the value of its input parameter, but that value immediately reverts to its former state once the function exits. I've pretty much come to the conclusion that it's a shortcoming of Perl and there's no way around it. I read somewhere that in order to modify a subroutine's argument you have to use @_ or $_, so I did. The same article said that as soon as you set some other variable to $v = $_ it will be impossible to modify the value of $_ afterwards. I think this may be happening when I call a method on the passed object reference or use a regular expression on a string. The subroutine takes a list of scalar parameters, the value of which may be either a reference to an object or a string. There's no way to do anything useful with it unless you know which one it is, obviously, so you have to at least check that. The program below "works," in that the input file(s) is processed and the output file is written without any errors (depending on the input file, I suppose) or warnings. The print STDERR $_ ; at the very bottom prints a string that has been modified exactly the way you'd expect, but when the function returns (usually to itself, in the case of a string) the string reverts to its previous value. I've tried various re-writings of the function to no avail. I've made $tree a global variable and that failed, too. I've pretty much decided that this is not going to work because of some shortcoming of Perl, but I've really only been playing around with Perl for about half a week now, so I'm pretty sure that the wisdome of the Perl Monks far surpasses mine. It's not a big deal or anything becauses there are several other ways to do it (and other languages to do it in, for that matter) but it just keeps nagging at me in the back of my head and I'd just like to know what the deal is here to satisfy my curiosity.
Update:I’ve been playing around with this code for a while and thought I'd post the latest version. The "main" function is more like it was when I started...
...with all the output going on here again. The only reason any output was being done inside the traverse sub to begin with was because I figured, "Hey, if I can't get at the modified strings here I'll just go in there and get them," but that hasn't panned out. The new version of traverse goes like this...
go_ahead() and curly_quotes() just do what the chunks of code they've replaced did, and they are working fine. Running the program gives me the following output at the command line:
but after running it the file output.txt looks like this...
...and I'm really wondering right now what that’s gonna like, but anyway... Given bellaire’s response and the other examples, I’m convinced that it really should work. I’m especially mystified that returning $element doesn’t work. I agree with ig and mr mischief that the HTML::Element involved here is probably conspiring against me and just not letting me change its content no matter what I do, probably by feeding me a copy of a copy of the string instead of the real one. I’ve experimented with the content_refs_list method as they suggested but so far without success. The main problem with that seems to be telling the difference between a reference to a string and a reference to an HTML::Element. I keep getting yelled at by Perl for calling methods on unblessed references and such, which makes me think that my strings are getting through the if (ref ${$element}) test, which they shouldn’t. I also had a mysterious incident at one point. I inadvertently left this line... ${element} = curly_quotes (${element}) ;...like that after changing the rest of the function back to what it had been, so that...
...actually ran and actually didn’t crash or complain or anything. I don’t see how (in a logical world, anyway) $element in the routine above got past the if (ref $element) test and into the else clause below it if it could be dereferenced safely. But I’m not pretending to be an expert on Perl after 3 or 4 days, either. Maybe Perl itself just expects occasional mistakes like that and works around them. ig probably has the answer here...
...or something very close to that. It's probably just a matter of figuring out where exactly to call those methods, etc. Thanks, everybody, for helping out. Update 2It works!
There’s the working version, in case anyone is interested. Took me awhile to get it going, though. For a while I kept getting yelled at by Perl for calling methods on unblessed references until I finally found the Scalar::Util::blessed() sub mentioned in the online documentation for Perl. Couldn't (or just didn't happen to) find it in the ActivePerl documentation. I still think that either one of these should have worked, but they didn’t...
The only difference between that version and the one that works is that the one that works does the for (@_) loop and this one just handles one parameter at a time. Shouldn’t make a difference but it does.
This one did some weird stuff. For some reason it will only run if you dereference child twice, which doesn’t make sense to me at all. It makes even less sense to me that it doesn’t work even though it runs, but both the versions above print an unaltered string in the print "Middle... line just after the traversal of $child. Oh, well. Although it did save me some work, the HTML::Element class gave me a lot of aggravation, too, and I found 3 major faults with it that I'm pretty sure are not my fault:
I find it extremely distasteful to mix object references and text strings in a list just generally speaking. If you don’t know which is coming when, there’s not much really useful about it since you can’t call a method on a string. If there’s not a package for a string class somewhere on CPAN (and I can’t believe there’s not even though I haven’t actually looked yet), there certainly should be. Even if there’s not whoever wrote the HTML package should have made an HTML::String object of their own descended from HTML::Element if they wanted (not like there’s actually much choice) to mix strings and elements in lists. I would have preferred to be using an XHTML package but I couldn’t find one. There&s an XML package but its parser looks like a pain in the butt to deal with (although, in hindsight, perhaps it would have been less painful to just dig into it anyway) and the XML::Simple package says that it won’t handle embedded content such as <b> tags inside of <p> tags. Oh, well. Thanks again for the wisdom. Cheers!
Back to
Seekers of Perl Wisdom
|
|