Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

RFC: Tutorial: use strict; now what!?

by Xiong (Hermit)
on Feb 08, 2012 at 09:32 UTC ( [id://952446]=perlmeditation: print w/replies, xml ) Need Help??

The following tutorial candidate is intended for rather raw newcomers. Some of the explanations may be a bit simplistic but I've tried to avoid giving too much detail. The newcomer already has much to absorb.

Hey! I see a lot of discussion of warnings. This tutorial is not about warnings. It's not even advice to add use strict; to a kiddie script; that's been given elsewhere, forcefully. I've made the assumption that the reader has already taken that advice. Now I want to show it wasn't bad advice.


Newcomers to Perl often are told to add a line near the top of script or module:

use strict;

Perhaps you've been so told and are now aghast to see your program halt unexpectedly with a new, possibly unsettling, error message. You may not feel you've moved forward. Before using strictures, your program just didn't work right. Now it blows up!

Purpose of Strictures

We often use strict; to prevent us from making stupid or careless mistakes. Perl is an extremely powerful and flexible language. You can do almost anything; but there are things you may not want to do. Sometimes we call these unsafe constructs. If Perl is the Swiss Army Chainsaw of programming languages, use strict; is the chainguard that keeps you from ripping off your own fingers. Use it for your own safety.

Without strictures, your code didn't do what you expected; but it did do something: the wrong thing. Now it blows up and does nothing, which is better than the wrong thing. Also, the error message tells you where you may have made a mistake and what seems to be wrong. This might be helpful and is a good place to start looking.

Strict Errors

There are (currently) three types of strictures: 'vars', 'subs', and 'refs'. When you write use strict; you are enforcing all three types.

The general format of such errors is:

(SOME_ERROR_TEXT) at (FILE) line (LINE). Execution of (FILE) aborted due to compilation errors.

You may not understand the SOME_ERROR_TEXT but you should start looking for a problem in FILE at LINE.

strict 'vars'

Example:

# Code: $x = 5; # no strict 'vars' print "$x\n"; # Output: Global symbol "$x" requires explicit package name at strict-demo.pl li +ne 10. Global symbol "$x" requires explicit package name at strict-demo.pl li +ne 11. Execution of strict-demo.pl aborted due to compilation errors.

Why: Perl itself does not require you to declare or initialize variables before you use them. The code is okay; but not under stricture.

Solution: Declare your variables:

my $x; # declare first $x = 5; # strict okay print "$x\n";

Reason: Avoid common typos such as:

$newPig = 'Keisha'; # much, much later... print $Newpig; # prints nothing; why?

strict 'subs'

Example:

# Code: my $subroutine = factorial; # no strict 'subs' print $subroutine->(7), "\n"; # Output: Bareword "factorial" not allowed while "strict subs" in use at strict- +demo.pl line 13. Execution of strict-demo.pl aborted due to compilation errors.

Why: A bareword, essentially, is anything that perl can't parse as something else. If you use a bareword then perl will try to interpret it; but perhaps not in the way you intended.

Solution: If the bareword is the name of a subroutine, then prefix it with the appropriate sigil ( & ). You probably also want to take a reference to it ( \ ):

my $subroutine = \&factorial; # strict okay print $subroutine->(7), "\n";

You may have intended your bareword to mean something else instead: $factorial, @factorial, %factorial, or 'factorial'. Fix it.

Reason: Don't make perl guess. The computer can't read your mind.

strict 'refs'

Example:

# Code: our $dog; my $pet = 'dog'; ${ $pet } = 'Rover'; # no strict 'refs' print "$dog\n"; # Output: Can't use string ("dog") as a SCALAR ref while "strict refs" in use at + strict-demo.pl line 18.

Why: When perl encounters ${ $pet } it constructs the variable indicated; which is ${ 'dog' } or just $dog. This is called a symbolic reference. Usually, you don't want to do this.

Solution: Avoid using the identifier of a variable as the value of another. You may find it useful to take a hard reference instead:

our $dog; my $pet = \$dog; # hard reference ${ $pet } = 'Rover'; # strict okay print "$dog\n";

Reason: perlref says it best: This is powerful, and slightly dangerous, in that it's possible to intend (with the utmost sincerity) to use a hard reference, and accidentally use a symbolic reference instead.

The Art of Debugging

Novices write code and run it; then they look at the output and try to decide if it's correct. If they're unsatisfied, they edit the code and run it again. Often they're confused because they don't know where things started to go wrong.

More advanced programmers try to write their code so, if it doesn't work properly, it will die: the program exits with a fatal error, displaying an error message including some suggestion of what went wrong and where. A first step is to use strict; which will catch many common coding mistakes.

Professionals write tests for their production code; these tests automatically exercise various aspects of the code. Testing is beyond the scope of this discussion but when you feel ready to step up, you are encouraged to study testing, starting with Test::Simple. I like to say that Test::More is the most important Perl module of them all.

When you first use strict; and encounter a fatal error, you may feel frustrated. Since you didn't intend to write one of these three types of unsafe constructs you may be wondering why you got the error you did. Often, what you thought you wrote is not what you really did write. Stick with it. Start with the first file name and line number given; check that line carefully. You may have to work backwards from there.

Quite likely, an error that pops up under strictures is merely a typo; it may be due to your misunderstanding of Perl. Study very carefully the standard resources:

You may want to look through the various perlfaqs, too. perltoc is a long list of all perldocs. You can get more help on the perldoc tool itself with perldoc.

no strict

At some point you will encounter code that turns strictures off, usually with one of the following lines:

no strict 'vars'; no strict 'subs'; no strict 'refs';

You may be tempted to do the same; don't. Yes, at some point you may become experienced enough to work without this safety net. But even experienced programmers avoid these unsafe constructs whenever possible. If they do disable strictures, they do so in the smallest possible scope.

When you see a no strict line, you may assume that the following code doesn't play entirely straight. Please don't try to write code like that!

Demo

Here's a script that includes all the above demonstrations. Comment or uncomment lines to see what works with and without use strict;

# strict-demo.pl # = Copyright 2011 Xiong Changnian <xiong@cpan.org> = # = Free Software = Artistic License 2.0 = NO WARRANTY = use strict; # comment out to avoid errors #--------------------------------------------------------------------- +-------# # Uncomment lines to force strict errors... # $x = 5; # no strict 'vars' # print "$x\n"; # my $subroutine = factorial; # no strict 'subs' # print $subroutine->(7), "\n"; # our $dog; # my $pet = 'dog'; # ${ $pet } = 'Rover'; # no strict 'refs' # print "$dog\n"; #--------------------------------------------------------------------- +-------# # Uncomment this whole section for a successful run... # my $x; # declare first # $x = 5; # strict okay # print "$x\n"; # my $subroutine = \&factorial; # strict okay # print $subroutine->(7), "\n"; # our $dog; # my $pet = \$dog; # hard reference # ${ $pet } = 'Rover'; # strict okay # print "$dog\n"; #--------------------------------------------------------------------- +-------# print "Done.\n"; sub factorial { my $in = shift; my $out = 1; for my $factor (2..$in) { $out *= $factor; }; return $out; }; __END__

Summary

The purpose of adding use strict; to the top of your scripts and modules is to force a fatal error instead of allowing your code to fail silently. It's your first and best friend in Perl.

Thanks

Changes

Suggestions for improvement are welcome and will be incorporated.

22012-02-07:
- new
I'm not the guy you kill, I'm the guy you buy. —Michael Clayton

Replies are listed 'Best First'.
Re: RFC: Tutorial: use strict; now what!?
by moritz (Cardinal) on Feb 08, 2012 at 09:50 UTC

    Very nice.

    From my experience though, beginners who use soft references should be using hashes instead, not hard references. It would be useful to add that solution too.

      beginners who use soft references should be using hashes instead,
      Hashes can be the solution. However, in almost all cases a hash based solution is done is such away it has all the disadvantages of not using strict, and none of the advantages.

      Writing $hash{key} isn't any better than no strict; $key. In fact, it's worse. If you don't have strict enabled, and you typo and write $kye (once), you still get a compile time warning (assuming they are enabled). If you typo $hash{kye}, at best you get a runtime warning of an uninitialized value, depending on how it's used. But you may get no warning or error, regardless whether you have strict or warnings enabled.

      Only if you would write:

      my $KEY = "..."; ... $hash{$KEY};
      you get protected against typos, but I very seldomly see people using hashes that way. But then you still don't get all the benefits of using regular, lexically scoped, variables:
      my $KEY1 = "something"; ... my $KEY2 = "something"; ... $hash{$KEY1} = "..."; $hash{$KEY2} = "..."; # Ooops.
      Perl will warn you if you declare a variable with the same name in the same scope. A benefit you lose if you implement variables as hash keys.

      For me, code that uses hashes as if the entries were variables is a red flag. It indicates the most dangerous type of programmer. It's someone who thinks he's past the grasshopper stage, but really isn't yet.

      Hashes as a bag of variables should be treated as Fugu. Only after 25 years of training, the first 14 of which all you do is cook rice 16h/day, 365 days/year are you allowed to look at the fish, and it takes another 25 years to master the slicing. Aka, it's only the experts, and they usually won't do it. It's certainly not for beginners.

      I rather see someone using a soft reference, than a hash as a bag of variables. That cure is worse than the disease.

        However, in almost all cases a hash based solution is done is such away it has all the disadvantages of not using strict, and none of the advantages.

        I disagree. Most beginner's uses of soft references are along the lines of

        while (<>) { while (/([a-z]+)/g) { my $word = $1; $$word++; } } print "I've seen the word 'compiler'\n" if $compiler; # similar checks for a few other variables here

        If you do that with a hash instead, you have a very clear benefit: you don't run into the risk of accidentally changing any our-scoped scalars in the current package.

        I am trying to follow this as I use hashes all over the place. What exactly is a soft reference. Perldoc says this:
        Symbolic references are names of variables or other objects, just as a symbolic link in a Unix filesystem contains merely the name of a file. The *glob notation is something of a symbolic reference. (Symbolic references are sometimes called "soft references", but please don't call them that; references are confusing enough without useless synonyms.)
        I understand the difference between hard and soft links in a filesystem, but in Perl?
        I rather see someone using a soft reference, than a hash as a bag of variables.

        Except that you can only use symbolic references with package globals in Perl 5, so you're susceptible to the risks of action at a distance.

        However, in almost all cases a hash based solution is done is such away it has all the disadvantages of not using strict

        Not even close.

        How is the following remotely the same as a program without strict:

        while (<>) { my ($k, $v) = split; $h{$k} = $v; } for my $k (keys(%h)) { ... $h{$k} ... }

      Thank you, moritz. I have given, in each of the three examples, code that fails a stricture; and a solution that passes strictures with exactly the same output as the failing code under no strictures. I'm not sure that's wise; it's merely simple.

      I'm a little afraid to step into the tar pit of Here are some of the things you might have been meaning when you got this error and here are some possible solutions. I did have the impulse and I agree that it might be helpful. Perhaps another node?

      If I see a proposed example and solution illustrating a strict 'refs' violation using a hash, I'll be glad to substitute it.

      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton
        I was going to say the same thing as moritz. In the spirit of your example, here is perhaps what was meant:
        my $pet = 'dog'; my %pet_name; $pet_name{$pet} = 'Rover'; print "$pet_name{dog}\n";
Re: RFC: Tutorial: use strict; now what!?
by ww (Archbishop) on Feb 08, 2012 at 12:40 UTC
    Nicely done!

    IMO, though, there are a couple minor instances of wording (not fact) that might mislead your target reader. So, herewith, some 'picky' comments:

    First para: "Before using strictures, your program just didn't work right. Now it blows up!" While NOT technically correct, I'd be inclined to surround the phrase "just blows up" it with quotes which some read (in this context) as signifying "ironic effect." Given that not everyone shares that view, perhaps typography could help: italicizing might highlight the irony.

    In the section, "Purpose of Strictures", you say (2nd para, 2nd sentence) "Also, the error message tells you where...." To my eye and ear, that sounds like an afterthought, diminishing it's importance. Maybe a <ul <li list with the two items thus (equally, to the eye) bulleted for attention. Esp. for the noobie, "where" is probably at least as important as "what" an error is... and by the time you mention "working backward from there" in the section on debugging, the noob may have gone off to try another iteration of the offending code.

    Under the "Strict Errors" subhead, would you want to add (perhaps parenthetically, after "You may not understand the SOME_ERROR_TEXT but you should start looking for a problem in FILE at LINE." a very brief note that an error message sometimes places the error one or more lines after the actual mistake?

    On the other hand, I wouldn't reorganize: your "chainguard" simile works very well and re-orging the following para would destroy the nice, natural transition you've created.

    Under "Strict Vars" it seems to me that you use the "Reason" subhead in a slightly different way that elsewhere. Rather than being augmented explanation of the prior point, it is, in this case, the introduction of a new one -- that strict helps catch typos (admittedly, only if the intended Var in question has been declared). This may be a tough one to enhance while staying concise.

    In Subs, I question restricting the advice to fix a bareword subcall to suggesting that the budding programming add an "&" -- re-ordering, subs first and predeclaring are at least equally valid.

    And, lastly, in line 5 of your (well-done) code, you say "# comment out to avoid errors." I would greatly prefer (well, you did mark this "RFC") "# comment out if you don't want Perl to help you find your errors."

      Thanks, ww, for the detailed critique. The pickier the better!

      ... blows up...

      <i>Now it blows up!</i> is italicized. We need to investigate if it doesn't show up that way for all. I used the phrase 'blows up' twice, in early attempt to show the newcomer sympathy with his viewpoint (likely, just shy of hysteria). Later I try to wean the newcomer onto orthodox concepts: '... die: the program exits with a fatal error...' but at the start I feel this too cold. Perhaps once is enough for metaphorical explosives:

      - Now it blows up and does nothing, - which is <i>better</i> than the wrong thing. + Now your code does <i>nothing</i>, + which is better than the wrong thing.

      This is of course technically untrue; the code does do something. But KISS.

      ... the error message tells you where...

      To anyone with even a little debugging experience, where is the most important question: where it do go blooey dammit?? That's where the search for something to change begins, the first clue in a fault hunt. Sometimes the fault is rightthere; sometimes it's far away; but we do generally start looking at the indicated FILE and LINE. So why don't I emphasize this?

      This tutorial assumes that the reader is a raw newcomer who has just now, for the first time, added use strict; to some code. I have spent quite a lot of time working with youngsters who encounter academic difficulty. These are kids whose solution, literally, for flat bicycle tire is buy new tire. Having seen the result of enforcing strictures, the intended audience of this tutorial will immediately think to remove the line that "caused the problem". I feel convincing the newcomer to retain strictures at all is most important.

      After inserting use strict; the next step is to begin debugging and not to delete the "offending" line. Showing how to find and correct the actual fault in newcomer's code is not really in scope of this tutorial.

      I do agree that this paragraph needs more work. I'll try some different stuff and see what I can improve.

      Strict Errors... one or more lines after the actual mistake...

      Sorry; but I think I'd rather go the other way and delete altogether:

      - You may not understand the <c>SOME_ERROR_TEXT</c> but you should - start looking for a problem in <c>FILE</c> at <c>LINE</c>.

      Art of Debugging is a mere taste but does cover this ground (in its proper place): Start with the first file name and line number given; check that line carefully. You may have to work backwards from there. I should use Strict Errors only to show the newcomer how to recognize that an error message is, indeed, a stricture error. Perhaps I should stick to the concrete examples.

      ... the "Reason" subhead...

      Reason: and Why: are redundant and lack focus. I'll see if I can't reorganize the examples so that each has only a single Why: section that explains clearly the fault in the example code. For all three examples, these sections are weak.

      ... bareword... subs first...

      Agreed. The example is contrived; the raw newcomer is unlikely to be passing callbacks around. More likely is invocation of a subroutine before it's been declared. I'll try that.

      ...# comment out to avoid errors...

      Agreed; a very poor choice on my part. I think I was wrong to suggest at all that the newcomer comment out use strict;. Rather, I should deploy the demo with it already commented out and invite the newcomer to activate it and enjoy the sauce.

      Also, ww, your "tiny nitpicking" leads to an important issue with the entire demo: The examples of "bad" code work just as well, without strictures, as the "good" code works with. So the demo does not demonstrate any value for strictures.

      I'm going to work over all the examples. For each example:
      • The "bad" code will run without strictures but produce "wrong" output;
      • The "bad" code will die under strictures;
      • The "good" code will run under strictures and produce "right" output.

      I hope this is feasible.

      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton
Re: RFC: Tutorial: use strict; now what!?
by educated_foo (Vicar) on Feb 08, 2012 at 13:39 UTC
Re: RFC: Tutorial: use strict; now what!?
by Eliya (Vicar) on Feb 08, 2012 at 15:10 UTC
    now what!?

    use warnings;  :)

    Seriously, I was a bit surprised to see no mention of warnings whatsoever.   Sure, you don't have to treat everything in a single tutorial, but if this is targeted at newcomers, recommending strict's equally helpful companion wouldn't do any harm, IMHO.

      Unlike strict, which is sometimes helpful and almost never harmful, warnings is very much a mixed bag, "use of uninitialized value" being the most obvious example of its harmfulness. Making it genuinely useful requires a lot of work (see e.g. common::sense), and most people aren't willing to put in that much effort. Lumping strict and warnings together is a mistake.
        Lumping strict and warnings together is a mistake.

        I beg to disagree.  Many times (not only here, but at my workplace, too) I've seen people hunting for bugs for way too long, simply because they thought "I don't need no stinking warnings".  Had they had them enabled, they would have been pointed to the root cause of the problem more or less directly.   And if you feel annoyed by the "use of uninitialized value"s (and you know what you're doing), it's no big deal to disable those specifically with no warnings "uninitialized"; — at least that doesn't qualify as "a lot of work" in my opinion.

        I agree there are rare circumstances where you don't want them — for example, I've seen a few cases (very few actually) where leaving warnings enabled in production environments has led to more problems than it solved — but as a development tool, I'd always recommend use warnings;

Re: RFC: Tutorial: use strict; now what!?
by RedElk (Hermit) on Feb 08, 2012 at 17:13 UTC

    Under Purpose of Strictures you wrote "We often use strict; to prevent us from making stupid or careless mistakes."

    Who are the ubiquitous "we" and "us"?

    A direct tone would work better. For example..."Use strict; to prevent stupid or careless mistakes".

    Also, the final sentence of this same paragraph is overly emphatic and not necessary. The chainguard metaphor makes your point very clear.

    My 2 cents.

      For example..."Use strict; to prevent stupid or careless mistakes".

      A direct tone can be useful. Combining a direct tone with the word "stupid" is probably... not smart. Yes, a "stupid mistake" does not actually imply that the actor is generally stupid. But I'm sure there will be readers who are... um... not fluent enough in English to realize that. The word "careless" is not much less loaded.

      I would suggest combining the direct tone with the phrase "typographical errors (typos)". Though, not having read the tutorial, there might be another approach that better fits into it.

      - tye        

      Agreed; delete:

      <c>use strict;</c> is the <i>chainguard</i> that keeps you from ripping off your own fingers. - Use it for your own safety.
      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton
      Who are the ubiquitous "we" and "us"?

      We cook your meals, we haul your trash, we connect your calls, we drive your ambulances, we guard you while you sleep.
      Do not fuck with us.

      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton

        That's cute.

        But, I'm not sure you got my point. The way you employ the ubiquitous "we" and "us" in your tutorial sounds like you're talking down to your reader. Not the right tone, in my opinion.

        A reply falls below the community's threshold of quality. You may see it by logging in.
Re: RFC: Tutorial: use strict; now what!?
by tangent (Parson) on Feb 08, 2012 at 15:59 UTC
Re: RFC: Tutorial: use strict; now what!?
by ikegami (Patriarch) on Feb 09, 2012 at 04:20 UTC

    I didn't have time to read the whole thing yet, but I saw a few oddities.

    "Execution of (FILE) aborted due to compilation errors." is not from strict itself, and is likely not to happen for 'refs' errors (since they are run-time errors). It's output for all compile-time errors, including run-time errors in files (modules) executed at compile-time.

    "A bareword, essentially, is anything that perl can't parse as something else." =~ s/anything/an identifier/; (e.g. "++++" does not contain an bareword.)

      Thanks, ikegami. As I mentioned in Re^2: RFC: Tutorial: use strict; now what!?, I'm already replacing the generic, abstract error with concrete examples. But sorry, I'm not willing to discuss (with my target audience) which portions of error output stem from which source or which phase of compilation or execution. We're splashing around in the very shallow end of the pool.

      Agree that my explanation of bareword is a little too loose. But I'd rather not introduce the term 'identifier' since that would only require yet another definition. The definition of bareword given in perldata is a tad too formal and perhaps even misleading:

      A word that has no other interpretation in the grammar will be treated as if it were a quoted string.

      I don't pretend to have a better explanation up my sleeve than what I've given so far; but I'm working on it.

      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton

        But I'd rather not introduce the term 'identifier' since that would only require yet another definition.

        "word", then.

        But sorry, I'm not willing to discuss (with my target audience) which portions of error output stem from which source or which phase of compilation or execution. We're splashing around in the very shallow end of the pool.

        I fully agree that you shouldn't backtrack after stating that strict outputs "Execution of (FILE) aborted due to compilation errors.". Specifically, you shouldn't say strict outputs "Execution of (FILE) aborted due to compilation errors." in the first place. Your own examples make a liar of you. Do you really want to give contradicting information to those you're trying to educate?

        (The common expression is "shallow end of the gene pool", which refers to lack of intelligence, not lack of competence. Let's not call the readers dumb.)

Re: RFC: Tutorial: use strict; now what!?
by sundialsvc4 (Abbot) on Feb 08, 2012 at 22:03 UTC

    I agree with the sentiments expressed here, including the use (not mentioned) of use warnings.   Basically, I think, the idea is to force as many dumb mistakes to be detected “at compile time” as possible.   When you are writing thousands of lines of code, little will typos creep in that you didtn recognize at the time.   And the time that you want to detect those isssues is, right now.   The computer has the amazing ability to detect the slightest inconsistency, and you want the computer to be doing everything in its power to assist you in that regard.   It will never encounter “Paris in the the spring” without instantly flagging the extra “the.”   But did you, while reading this, encounter every one of the five tpyos I put in here?   (If your browser underlined them for you, it doesn’t count.)

    If you find that you must use a construct that flags a warning, you can use the no construct, and liberal and detailed comments, to explain exactly what you are masking-out and exactly why.   (You will not remember, even with regard to your own code.)   Then turn the feature right back on as soon as possible.

      But did you, while reading this, encounter every one of the five tpyos I put in here?
      I didn't! And yet, I fully understood what you were trying to express. I vastly prefer to autocorrecting my mind does (without even being aware of it) of your readings than throwing an exception on each of your typos.

      So, for me, your argument is really "if you prefer 5 interrupts when reading a single paragraph, instead of just do ing the right thing, use strict; is just the tool for you". Now, don't get me wrong, I often use strict myself, but I find your "spotting the typos" example a very convincing argument.

        I assume your reply was quite clever intentionally. All your arguments seem to be against his typo metaphor, yet you conclude by saying that it is "very convincing".

        Sure, I could conclude that your presumed error was done intentionally to further illustrate your point. However you have also included so many other errors (relative to word count) that my own mind threw several exceptions while reading your response. Thus the syntax of your argument against his metaphor actually supports it. So what meaning were you truly trying to convey?

        I'm reminded of Paul Atreides thoughts on Harkonnen plotting: "plans within plans".

Re: RFC: Tutorial: use strict; now what!?
by tangent (Parson) on Feb 15, 2012 at 08:52 UTC
    Bit late but I came across this reply to a post moaning about having to use strict and my which sort of drives it home:
    But when respiratory system of your mom will be under your code, you’ll think hundred times to check that every variable is declared instead of appearing from nowhere.

      I appreciate your support but please excuse me if I say that the purpose of this tutorial will not be to emphasize to the newcomer the importance of strictures. This has been done better elsewhere and better than I would presume to attempt.

      Rather, I assume that the reader has already been lectured, already taken the advice; and now is dismayed to find the program appears to have taken a step backwards. This is the context in which I believe runrig made his offhand suggestion. (For any misunderstanding I take all responsibility.)

      The newcomer now needs to know what to do next and, perhaps, needs to see concretely how the apparent burden of strictures can be employed as a blessing.

      I'm working on it.

      I'm not the guy you kill, I'm the guy you buy. —Michael Clayton
        Hence the "now what!?" in the title. Got it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://952446]
Approved by moritz
Front-paged by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (6)
As of 2024-03-19 05:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found