When to "use strict" when teaching?

U

Uri Guttman

SM> Pretty much my thinking:
SM> 1. It doesn't hurt anything (that I know of)
SM> 2. It makes it pretty clear where the end is, especially for newbies.

and i have another use i just recalled. during development i may have
some of the earlier top levels subs being tested but the later ones
either aren't ready or they need good results from the ealry subs. so i
will just drop an exit in there to stop the program. sometimes i have
done this inside a sub to help isolate the part i am debugging. why run
later code which could generate output (which is noise to me at this
moment)? an early exit does what i want nicely.

i am sure there are other uses for it. i use die much more often but
exit has its place.

uri
 
B

Brian McCauley

When I do three-day intro classes, I introduce subroutines early in
the afternoon of day 2. The next section of the class is about 'my'
variables, because there's no use for 'my' variables until...

Now I know you have more experience of teaching but I think this is
arse-about-face. I suspect your idea of the logical idea to introduce
concepts is being influenced by the history of Perl (in the same way
as feotal development seems to mirror evolution).

Most languages don't have implicit variable declaration. I see no
reason to introduce the concept so early.
... programs are big enough to need to have subroutines.

I know that when people are first leaning a language they tend to
write really short programs. I also know that implicit quoting of
strings and implicit variable declaration can be a handly techniques
when writing very short programs. (Once again, I think it makes more
sense to express it in that positive way than your negative way).

However, the students are not learning to write small programs in
Perl. They are learning Perl. The correct place to introduce "no
strict qw( subs vars)" is in the lesson where one talks about special
techniques for one-liner programs and the command line switches -e -F
-l -n -p and so on.

(The correct place to introduce "no strict qw(refs)" is in "advanced
techniques" along with GLOBs and AUTOLOAD methods).
The motivation for all three features is similar. You want
subroutines for modularity and reusability. Subroutines that refer to
global variables are neither modular nor reusable, so you need 'my'
variables. And 'strict vars' helps you remember to declare the
variables.

You are letting your knowledge the evolutionary history of Perl bias
you towards seeing "use strict" as adding features. It is not. For
someone looking at Perl5 afresh it is more appropriate to see it as
switching off rarely useful features (implicit quoting, implicit
declaration of unqualified package variables, symbolic references) that
are enabled by default for largely historical resons.
I don't cover 'strict refs' until the following afternoon, after
we've seen references; then I can discuss the serious and
untraceable problems that can be caused by accidental use of
symbolic references.

In a 3-day class probably would never mention in detail the
consequences of omitting "use strict". (Actually that depends on the
audience - a 3-day course for Unix sysadmins probably would include
the lession about one-liner programs and the command line switches -e
-F -l -n -p).
I think the philosophy that says that you should always have 'use
strict' at the top of every program from the start of day one is
misguided.

I disagree.
The theory is that you're training people to follow good
programming practices.

That's not my theory. Teaching them to follow good practice is
separate. Given that we're doing that anyhow "use strict; use
warnings;" just makes life easier for them.
But this theory somehow manages to forget that
putting stuff into your program when you don't know what it does is
the very worst of all possible programming practices.

When I say "use MODULE" I only need to know what it does upto some
level. The whole point about modularisation is that I don't need a
full understanding of the internals.

I would tell them the truth: "use strict" disables three features of
Perl that are only rarely useful and make debugging a whole lot harder
if you accidently use them when you didn't intend. If my students are
smart they'll ask why are these features enabled by default. The
answer I'd give is: "party history and partly because two of these
features are primarily useful in one-line scripts where the overhead
of having to explicitly switch them on would be proportionately very
high".

That is enough. They now understand why it is that omitting "use
strict" should be considered a positive action.

Once I've given them enough information for them to understand why
omitting "use strict" should be considered a positive action that very
same argument "putting stuff into your program when you don't know
what it does is the very worst of all possible programming practices"
now applies to leaving out strict.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
M

Mark Jason Dominus

I suspect your idea of the logical idea to introduce concepts is
being influenced by the history of Perl

It isn't.
You are letting your knowledge the evolutionary history of Perl bias
you towards seeing "use strict" as adding features.

I am not.

I see that you have promoted your suspicion from the first paragraph
to the status of a fact. In the future, you might want to be careful
that you don't forget which things are factually true and which are
the ones that you invented a few minutes before. I think it makes you
look foolish.
It is not. For someone looking at Perl5 afresh it is more
appropriate to see it as switching off rarely useful features
(implicit quoting, implicit declaration of unqualified package
variables, symbolic references) that are enabled by default for
largely historical resons.

I think this is a revisionist point of view. Yes, a lot of the
programs that people wrote in Perl historically are short scripts that
don't need 'strict'. But so are a lot of the programs that people
wrote yesterday afternoon.

Those features were originally enabled by default because they were
useful and convenient. Today, that cannot be changed, for
compatibility reasons. But even if they could be disabled by default,
it is not clear that would be the best thing to do, because they are
still useful and convenient.

In a 3-day class probably would never mention in detail the
consequences of omitting "use strict".

I have a number of objections to that. Some are practical, and some
are ethical.

Here is a practical objection. On day 4 you have gone home. Your
student is writing a program, and it dies in the middle. So they
spend a couple of hours puzzling over what might be wrong, and perhaps
changing stuff around at random because that's what a lot of
programmers do when they encounter an error message they don't
understand. Then they send mail to the guy in the next cubicle, who
was also in your class, saying

Hey, my program doesn't work; it says:

Can't use string ("ARRAY(0x8113f74)") as an ARRAY ref
while "strict refs" in use

What's wrong?

So you taught them to "always use strict", but it didn't do your
student very much good. They have a real error, and the program died,
and now they don't know what to do because you never showed them the
error message or explained what it was about.

Now what happens next? One thing that often happens in your scenario
is that the guy in the next cubicle writes back:

I got that message too, but getting rid of the "use strict"
made it go away.

which of course is a disaster. And the students are not equipped to
understand why that would be a disaster, or to understand the kinds of
problems that arise as a result, because you never mentioned in detail
the consequences of omitting "use strict".

It would be better if the guy in the next cubicle could say

I think that message means that you used a string as if it was
a reference. That ARRAY(0x8113f74) thing looks the way a
reference does when you print it out. Maybe your reference
turned into a string somehow?

and then maybe the first guy says

That sounded awfully familiar, so I looked in the notes we got
in the class and found it on page 142. Thanks!

This might happen in my class, but it can't happen in yours, because
you never mentioned in detail the consequences of omitting "use
strict".

You started out the post by suggesting that I was motivated by an
obsolete historical view of the development of Perl. But that's not
it. I'm motivated by a philosophy that says, in part:

* Programming can't be done by rote.

* More understanding is always better; less is always worse.

* Don't leave out anything important. But if something is
important, you should be able to explain why it is important.

'strict' is important, which is why I put it in, and why I want to
explain *why* it is important. ("Here's what could happen if you
don't put it in.") I don't think that it works to try to put it in
without including the reason why, and I think it's disrespectful to
the students to try to do that anyway. They're adults, they're
professionals, and we should suppose they can be trusted to make the
right professional decisions when provided with the facts.
That's not my theory. Teaching them to follow good practice is
separate. Given that we're doing that anyhow "use strict; use
warnings;" just makes life easier for them.

I think this may be the basis of our disagreement. I think you are
completely wrong here. Good programming practice does not exist in a
vacuum. It was not handed down by God from Mount Sinai. Good
programming practice is precisely the set of practices that make life
easier for programmers. How can making life easier be separate from
following good practice?

There is no such thing as a good programming practice that does not
make life easier, or a bad programming practice that does not make
life harder. If something makes life easier, it is good programming
practice; if it makes life more difficult, it is bad programming
practice. How could it be otherwise?

It is good programming practice for functions to use only lexical
variables. Why? Not because all the books say so. It is because
functions that use global variables are hard to maintain and reuse,
and make life more difficult. Life is easier when functions use only
lexical variables. And that is *why* all the books say so.

It is almost always good programming practice to have 'strict refs'
declarations active in your Perl program. Why? Not because all the
books say so. Not even because Brian McCauley says so. It is because
'strict refs' helps catch certain kinds of run-time errors that would
otherwise make life difficult. Life is easier when 'strict refs' is
on. And that is *why* all the books say so and why you say so too.

Sometimes, in peculiar circumstances, life is easier when a function
uses a global variable for something or other. In these peculiar
circumstances, using the global variable is good programming practice.
Sometimes, in peculiar circumstances, life is easier when 'strict
refs' is off. In these peculiar circumstances, using turning off
'strict refs' is good programming practice.

Many times I have seen people following completely blockheaded
programming practices that are promulgated because they were
supposedly 'good programming practices'. Many real programs are
tremendously complicated because some ass got stuck on some theory of
'good programming practice' and forgot that 'good programming
practice' should be grounded in the reality of what makes real
programs easier to write and maintain.

One common pattern, for example, is the 100-line script whose first 40
lines are

my (%index_hash,
$dev_type,
$ref_label
... (35 more omitted)
$read_dir_def,
$write_dir_def);

So you ask "Why does your program start off with 40 lines of
declarations?" and the answer is "Because otherwise it doesn't work
under 'strict'." This is a fine answer as long as there is more to
it, like "...and I decided that the cost of maintaining the
declaration was worth paying for the benefit of getting spelling
errors diagnosed in variable names."

But if the rest of the answer is "I don't know but someone told me
that everyone should always use strict all the time," it's a lousy
answer. That is exactly cargo-cult programming. There are two
problems with cargo-cult programming. The two problems support each
other.

The first problem is that cargo-cult programming promulgates
ineffective or destructive programming practices by elevating them to
that status of 'good programming practice'. Then people use the bad
practices just because they are labeled 'good'. Even when a practice
are generally good, there is usually some circumstance in which it
should be avoided, because hardly any practice is always good. But
cargo-cult programming promulgates the use of the 'good' practices
even in circumstances for which they are unsuitable.

The second problem of cargo-cult programming is that the labeling
process discourages critical thought about the meaning of the labels.
People are encouraged to adhere to certain practices because they are
'good', and to avoid others because they are 'bad'. The goodness and
badness have become divorced from anything in reality; people
habitually select practices based on the labels, and not based on
reality. They forget that there *is* an underlying reality, as the
labels become the end goal, rather than a means to achieve an end goal
of making life easier. As people lose track of the end goal of making
life easier, life becomes more difficult. Programmers adopt bad
practices because some yahoo has labeled them 'good' and because they
have lost the ability to look at the end result of the practices and
judge for themselves.

Telling people to do stuff that they don't understand often appears to
make things easier for them, but it only does so in the very short
run.

In the medium term, you are just setting up a bigger, nastier
programming surprise for them, when they get the error message (that
you told them to enable) and they don't understand what it means or
how to diagnose or repair the problem that it represents.

In the long term, you are failing in your duty as a teacher, by
encouraging ineffective patterns of thought. Instead of encouraging
"this is what 'use strict' does and this is when and why I would want
to use it", you are encouraging "Brian says to do this, so I will."
In the short term, that might work, but it will not help the student
become a better programmer.
When I say "use MODULE" I only need to know what it does upto some
level. The whole point about modularisation is that I don't need a
full understanding of the internals.

You are confused about what I said. (Or else you are twisting my
words, but I'll give you the benefit of the doubt.) I did not say
"when you don't know how it works". I said "what you don't know WHAT
IT DOES".

We are not talking about the internals here. I am not advocating that
people should understand that behavior of the $^H variable before
using 'strict'. I am advocating that that should know WHAT IT DOES.
I would tell them the truth:

But not the whole truth. You'll tell them the policy, but not the
technical reality that led to the policy. But that's what I find
disrespectful. These profesionals are supposed to be able to
understand the technical aspects of the policy, but you're not giving
them enough information to do that. If you think that the
programmer's job is to unquestioningly implement the policies laid
down by his supervisor, it's enough. But I don't think that, and I
think it's unethical to promulgate that idea.
Once I've given them enough information for them to understand why
omitting "use strict" should be considered a positive action that very
same argument "putting stuff into your program when you don't know
what it does is the very worst of all possible programming practices"
now applies to leaving out strict.

That is a phenomenal display of doubletalk. ("Ignorance is Strength!")
Regardless of the merits of the rest of your post, I feel sorry for
you that you could write this last paragraph without realizing what a
load of bullshit it is.
 
C

Charlton Wilbur

MJD> I don't think that it works
MJD> to try to put it in without including the reason why, and I
MJD> think it's disrespectful to the students to try to do that
MJD> anyway. They're adults, they're professionals, and we should
MJD> suppose they can be trusted to make the right professional
MJD> decisions when provided with the facts.

We should suppose this, and often we do; which means that we get
burned even worse when we're wrong. Perhaps this is more a comment on
the caliber of the programmers I've worked with than on any
pedagogical techniques, but when I was charged with writing Perl
coding standards at a prior place of employment, I made strictures and
warnings mandatory -- not because I think they ought to be mandatory
in all cases, but because I don't think the sort of judgment that
allows a programmer to correctly determine whether he's better off
without them is something that arises after a few training sessions.

(The principal benefit of having it in the coding guidelines was that,
in a hypothetical code review, "why aren't you using strictures?" was
likely to be one of the first questions asked. Practically speaking,
the only other person who wound up writing any Perl was immune to code
reviews, and thought he was above strictures and warnings anyway,
which meant I spent nearly as much time rewriting his code as he spent
writing it in the first place.)

MJD> There is no such thing as a good programming practice that
MJD> does not make life easier, or a bad programming practice that
MJD> does not make life harder. If something makes life easier,
MJD> it is good programming practice; if it makes life more
MJD> difficult, it is bad programming practice. How could it be
MJD> otherwise?

But there *are* good programming practices that can make things harder
in the short term, and bad programming practices that can make things
easier in the short term. (Usually there's a lot of luck involved in
the latter.) It takes experience and the wisdom that comes from
reflecting upon experience to learn to weigh long-term good versus
short-term good, especially in an environment with multiple deadlines
and multiple projects and multiple goals which are constantly
changing. This is why good programming practices are taught in
schools and specified in coding guidelines, rather than allowing each
programmer of indifferent talent to reinvent them from the ground up.

MJD> The first problem is that cargo-cult programming promulgates
MJD> ineffective or destructive programming practices by elevating
MJD> them to that status of 'good programming practice'. [...]

MJD> The second problem of cargo-cult programming is that the
MJD> labeling process discourages critical thought about the
MJD> meaning of the labels. People are encouraged to adhere to
MJD> certain practices because they are 'good', and to avoid
MJD> others because they are 'bad'. The goodness and badness have
MJD> become divorced from anything in reality; [...]

Again, this may have more to do with the caliber of the programmers
I've worked with, but critical thought seems largely absent whether
cargo-cult programming practices are mandated or not. I concur that
in a perfect world competent professional programmers would weigh the
benefits of strictures and use them when appropriate, but I've also
observed that in this imperfect world not only are many of the people
employed as programmers neither competent nor professional, they have
little interest in achieving either status.

And so, the question becomes - what do you do when you recognize that
rules do not substitute for good judgment, but all you have is
mediocre to bad judgment, which may become good judgment in time? I
think the approach that you advocate is the correct one -- explain
strictures when it's pedagogically appropriate (which may mean "I want
you to notice this line now, and for the time being include it in all
your programs; we're going to discuss in depth what it does in session
8, after we've talked about some other concepts that it relates to,
but for now what you need to know is that it will make some types of
errors much easier to catch"), and strongly recommend that they be
used in all programs until the programmers have good reason to turn
them off.

Charlton
 
B

Brian McCauley

I see that you have promoted your suspicion from the first paragraph
to the status of a fact.

Sorry, I should have said "postulate" not "suspect".
I think it makes you look foolish.

I think idea of the implied postulate is not uncommon in causual (as
opposed to formal) rhetoric.
I think this is a revisionist point of view.

Sure is! Indead what I accused you of "letting your knowledge [...]
history [...] bias you" essentially the same as saying you are not
prepared to accept a revisionist point of view. So if you reject my
view because it is revisionist you support my thesis. :)

But this is not a debating society and all this meta-discussion is OT.
Yes, a lot of the
programs that people wrote in Perl historically are short scripts that
don't need 'strict'. But so are a lot of the programs that people
wrote yesterday afternoon.

Yes, and as I said before - if my students were the "tradition" Perl
users (Unix sysadmins) then I'd probably want to include early on a
lesson of tricks to use in really short scripts.

However even in the above case, general programing examples, even
short ones, should always be presented as if they were part-of (or
expected to grow into) a much larger program.
Those features were originally enabled by default because they were
useful and convenient. Today, that cannot be changed, for
compatibility reasons. But even if they could be disabled by default,
it is not clear that would be the best thing to do, because they are
still useful and convenient.

Right, I postulate that here we're talking here about 'subs' and
'vars'.

I recon the only time that having these strictures off is a nett gain
is in -e scripts.
I have a number of objections to that. Some are practical, and some
are ethical.

"Never let your sense of morals prevent you from doing what is right."
-- Isaac Asimov (Foundation)
Here is a practical objection. On day 4 you have gone home. Your
student is writing a program, and it dies in the middle. So they
spend a couple of hours puzzling over what might be wrong, and perhaps
changing stuff around at random because that's what a lot of
programmers do when they encounter an error message they don't
understand. Then they send mail to the guy in the next cubicle, who
was also in your class, saying

Hey, my program doesn't work; it says:

Can't use string ("ARRAY(0x8113f74)") as an ARRAY ref
while "strict refs" in use

What's wrong?

So you taught them to "always use strict", but it didn't do your
student very much good. They have a real error, and the program died,
and now they don't know what to do because you never showed them the
error message or explained what it was about.

How do you conclude that?

An understanding of how symbolic references work is neither necessary
nor sufficient to understand that message.

To understand that error you only have to understand that if you
use a string in a reference context it's an error. This will seem
quite natural to most people with normal programming experience and
you shouldn't need to go to great lengths to justify it.

You also need to know what happens if you use a reference in a string
context.
Now what happens next? One thing that often happens in your scenario
is that the guy in the next cubicle writes back:

I got that message too, but getting rid of the "use strict"
made it go away.

which of course is a disaster. And the students are not equipped to
understand why that would be a disaster, or to understand the kinds of
problems that arise as a result, because you never mentioned in detail
the consequences of omitting "use strict".

Indeed I have seen it happen. But only in the case of people who
tried to retro-fit strictures to their Perl programming. That is why
I say don't expose people to the idea of omitting "use strict" until
you are prepared to explain the consequences at least in part.

So, as I said above, to understand the _cause_ of the above error you
don't need to understand anything symbolic references.

Futhermore, to understand why the error message mentions "strict" you
still don't need to understand anything about symbolic references.

It is sufficient to know that if you were to remove "use strict" Perl
will think you were wanting to use some obscure "feature-X" that
you've not yet learnt about because you had more interesting things to
do. You only have to understand feature-X if you want to use it or if
you want to understand the entertaining results of the Perl
interpreter thinking you wanted to use feature-X when you didn't.
It would be better if the guy in the next cubicle could say

I think that message means that you used a string as if it was
a reference. That ARRAY(0x8113f74) thing looks the way a
reference does when you print it out. Maybe your reference
turned into a string somehow?

This outcome is no more or less likely as a result of teaching them
about symbolic references.
and then maybe the first guy says

That sounded awfully familiar, so I looked in the notes we got
in the class and found it on page 142. Thanks!

IMHO people should, where possible, be encouraged to use reference
manuals, not notes from a tutorial, as reference manuals.
This might happen in my class, but it can't happen in yours, because
you never mentioned in detail the consequences of omitting "use
strict".

In my (hypothetical) class I told them that "use strict" disabled
three features of Perl (not covered in my class) that cause havoc if
you use them by accident.
You started out the post by suggesting that I was motivated by an
obsolete historical view of the development of Perl.

No, I didn't claim it _motivated_ you.
I'm motivated by a philosophy that says, in part:

* Programming can't be done by rote.

I agree. But poeple do pick up habits by rote. It cannot be avoided.
When you provide programming examples (not directly addressing the
question of variable scoping) you either do declare all variables as
lexicaly scoped in the smallest applicable scope or you don't. You
either put "use strict;" at the top or you don't. You can't avoid it.

Whichever you do will cause them to tend to do the same in their code
by rote.
* More understanding is always better; less is always worse.

* A little knowledge is a dagerous thing.

Let us imagine a graph of "level of understanding" v "goodness" (or
whatever you choose to call the metric that defines your terms "better"
and "worse").

While I agree that the overall trend is upwards the local gradient may
be negative in places.

Also you can't, in a course of finite length, consider the
understanding of any one aspect of the subject matter in total
isolation. Any time spent giving a deeper understanding of one aspect
must necessariliy be compensated for by covering some other aspect in
less detail.
* Don't leave out anything important. But if something is
important, you should be able to explain why it is important.

I agree totally. Explain enough to see why it is important. That is
not the same as explaining all the details.
'strict' is important, which is why I put it in, and why I want to
explain *why* it is important. ("Here's what could happen if you
don't put it in.") I don't think that it works to try to put it in
without including the reason why, and I think it's disrespectful to
the students to try to do that anyway.

I think it's disrespectful to assume that they can't decide if they
want look up the reason for themselves.
They're adults, they're
professionals, and we should suppose they can be trusted to make the
right professional decisions when provided with the facts.


I think this may be the basis of our disagreement. I think you are
completely wrong here...

[ snip ~100 lines of things I agree with totally and indeed have
argued myself many times in the past ]

Since I agree with all those things I don't think any of that can be
the basis of the disagreement.
We are not talking about the internals here.

No, you are right. Poor choice of words.
I am advocating that they should know WHAT IT DOES.

So am I.

It may also be interesting to know what NOT DOING IT DOES. But that's
not so important that I'd want to displace other matters from a 3-day
course in order to cover it.
But not the whole truth.

Of course not. Do you tell the whole truth about everything (first
time) when teaching Perl?

For example, consider when you first teach people about:

$coderef = \&foo;

Do you tell them that if &foo is already defined it creates a
referenece to the current definition of &foo and will continue to
point to that same function even if &foo is subsequently deefined?

Do you also tell them that if &foo it is not yet defined it creates a
reference that acts through *foo{CODE} and will henceforth refer to
whatever definifion &foo has at that time?
You'll tell them the policy, but not the technical reality that led
to the policy. But that's what I find disrespectful. These
profesionals are supposed to be able to understand the technical
aspects of the policy, but you're not giving them enough information
to do that.

I'm not just telling them the policy. I'm telling them enough of the
technical reality that led to the policy that they can see that the
policy probably makes sense. I have alluded to the fact that there
are times when the policy should be broken. I respect them enough to
figure they are capable of understanding that I have chosen to abridge
the explaintion so as to leave time for other things. I respect them
enough let them make the judgement as to if they want to look up the
rest of the information.
That is a phenomenal display of doubletalk.

Thankyou. :)
("Ignorance is Strength!")

Ignorance is strength - up to a point. Or rather, deciding which
things not to try to understand (yet) is a very important part of
learning anything.
Regardless of the merits of the rest of your post, I feel sorry for
you that you could write this last paragraph without realizing what a
load of bullshit it is.

Obviously I was decending into self-parody. Nontheless I still stand
by the underlying idea:

Just because an act is an act of omission does not necessarily exempt
that act from the rule that you shouldn't do things you don't
understand.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top