Pages

A blog about teaching Programming to non-CompSci students by Tim Love (Cambridge University Engineering Department). I do not speak on behalf of the university, the department, or even the IT group I belong to.

Tuesday, 6 May 2014

Which computing language for engineers?

At our site we teach general engineering - students amongst other things can learn AI, Economics, and bridge-building. Which language should they be taught? Though their needs are different from those of Computing students and of more specialist (e.g. Electrical) Engineering students, their programming needs may be extensive. In Teaching Introductory Programming in Tertiary Engineering Education M.G. Rashed points out that "Computers are increasingly used for a variety of purposes in engineering and science including control, data analysis, simulations and design optimization. It is therefore becoming more important for engineering students who are computer science non-major, to have a robust understanding of computing and to learn how to program". It's over 15 years since we last changed the primary language (I've found a document from 1996 which addresses the issue - Teaching Programming in the Engineering Tripos). In that time much has changed in the world of engineering, so a review of our language choice is timely.

YearEvent
1985Pascal as a 1st language
1996?Matlab as a 2nd language
1997C++ as a 1st language
???Compulsory computing questions
in the 1st year exams.
2008Vacation C++ exercise
20101st week Lego Mindstorms (Matlab)
2012C++ course flipped - 25% more labs
at the expense of lectures

Factors

Firstly then, what factors should influence our choice, and how have those influences changed over the years? Here are a few -

  • The value of programming in general - When I was taught Latin at school I was told that it was good for me, it trained my mind. Nowadays Mandarin might be taught on the grounds that it's a common language, or Esperanto because it's an easily learnt, well-designed one. Similar differences of opinion apply to computing languages. Programming skills might have intrinsic value or be widely transferable. According to its advocators, Computational Thinking "involves a set of problem-solving skills and techniques that software engineers use to write programs ... However, computational thinking is applicable to nearly any subject. Students who learn computational thinking across the curriculum begin to see a relationship between different subjects as well as between school and life outside of the classroom. Specific computational thinking techniques include: problem decomposition, pattern recognition, pattern generalization to define abstractions or models, algorithm design, and data analysis and visualization".
  • The value of programming for engineering - M.G. Rashed thinks that "The primary target in teaching computing is to enable the students to convert engineering problems into pseudo-code. ... The conversion of this pseudo-code into a program written in one programming language is of secondary importance because it is, in principle, an algorithmic procedure and requires less intellectual effort. ... In the teaching practice, the algorithmic problem- solving and implementation tasks are often entangled simply because the students need to test an algorithm they invented by implementing it. Consequently, the choice of the teaching language should be governed by which language provides the best support to the student in performing the implementation part of the problem-solving task by removing any extra stumbling blocks. For this reason the usefulness of the language after graduating or speed of execution will not be the prime factors when making the choice."
  • Requirements of other courses - some other courses assume specific aspects of computing competence.
  • Students' previous experience - A long time ago many students arrived with some programming experience thanks to home micros running BASIC and schools equipped with BBC micros. Then skills fell away. More recently, with free Linux being available, and raspberry Pi kits on sale, there's been a recovery in programming skills, but only amongst the computer literate, meaning that the distribution of our intake's computing skills is more bi-polar than ever.
    Though they may program less than earlier generations did, they use computers far more. In particular they rather expect there to be an app for everything - to supply documentation, to provide an interface to hardware (instead of a remote being provided, etc). They may hope that what they produce looks rather like an app.
  • Industry relevance - Anecdotal comments from staff suggest that some companies aren't convinced that we are preparing our students for programming. C is more useful for embedded systems than C++. Matlab experience is often requested. One problem is that the needs of industry change, and aren't easy to predict long enough in advance. The invention of the WWW and cheap, small processors has led to the use of GPS and intelligent sensors in civil engineering projects. Google Maps and Google Apps enrich projects as well as aid communication between workers. One student wrote to me that "surely as a professional chartered engineer if you need to do some programming/coding you would hire a professional who would do it in no time at all plus do it correctly" but it would be a shame if the engineer got ripped off because they hired professionals to write trivial or poorly-spec'd software.
  • Language features - ease of use, expressiveness - Despite the popularity of languages such as FORTRAN and C/C++, there has been much debate about the suitability of these languages for education, especially when introducing programming to novices. These languages have not been designed specifically for educational purpose, nor do they make for easy use of the WWW or creation of GUIs. Interpreted languages are growing in popularity (the image is from the M.G. Rashed paper).
  • Availability of compilers, IDEs, and teaching materials - We've had some trouble providing easily-installed C++ IDEs across platforms. All the teaching materials are on the WWW. Web2 technology has been exploited -
    • Documentation for the 1AC++ Mich course is now WWW-based with online PHP-based teaching aids.
    • A 2nd year C++ course went a step further, incorporating online marking.
    • The Mars Lander project uses CamTools to host documentation and student-staff communication
  • Availability of teaching staff - With class sizes of 90 or so, computing practicals require several skilled helpers.
  • Learning styles - Teaching remains based on practicals with demonstrator support. There are fewer lectures. Independent study has been encouraged by providing the MDP disc, giving help to students installing compilers on their own machines, and changing teaching material so that documentation is on the WWW, the exercises requiring the minimum of extra libraries.

Candidate languages

  • Matlab/Octave - Students use this in week 1. Only in year 2 are they more formally taught it. Matlab has a large range of material produced by univs for ugrads, much of it with a math/engg bias. In a Mathworks newsletter, staff at Vanderbilt University write that "engineers from five major companies ... credited MATLAB with helping them become more efficient and achieve time reductions 'from a week to 15 minutes' and 'from several months to weeks'" citing an automotive engineer’s statement that "MATLAB was a de facto industry standard". Many engineering-related routines and program are available.
  • Python - According to Charles Dierbach ("Journal of Computing Sciences in Colleges" 29, 6 (June 2014)), "The Python programming language has been quickly gaining popularity over the past few years as a language of choice for CS1 courses. Some estimates put the rise in use at forty-percent a year". "The Python programming language has been around since its development by Guido van Rossum around 1991. One of the main features of the language is code readability (sometimes described as "executable pseudocode"). Python is an interactive programming language, using dynamic typing. It is also a hybrid language, supporting the imperative, object-oriented and functional programming paradigms. Although used as a scripting language, it is also used for the development of full-scale programs." The University offer courses in Python for number-crunching, etc. Many engineering-related packages are available.
  • C++/Objective-C/C# - Students use C++ for about 20 hours in year 1 and at least another 8 hours in year 2. In a Cambridge university C++ course it says "Unless you are already a programmer, you are very strongly advised to learn Python first ... learning another programming language would also do. “Programmer” does not mean in Visual Basic, Excel or even most uses of Matlab; it means in Python, Fortran, C, Pascal etc. It surprises most people, but learning simpler languages first often saves time overall. ... You can learn to use any of these (even Fortran) to a comparable level in about 20% of the time that you will need to learn C++"
  • Java - one piece of 3rd year coursework currently requires students to write Java. Their C++ experience is presumed to be a sufficient prerequisite.

Multilingualism

Are there advantages in principle in exposing students to several languages? Ultimately it's unavoidable, though perhaps initially it confuses people. We don't compare/contrast languages. We tend to leave that to the students.

Thursday, 27 March 2014

Some educational myths

Well, not myths really, but it's sometimes worth challenging cherished notions

Deep down, students know what's good for them

In "Student interest and choice in programming assignments" (Journal of computing in small colleges 26, 6 (June 2011)) Lisa Torrey surveyed 14 students to find out what motivates their choice of programming exercises. She'd hoped that students would choose programs at the optimal level of challenge but found that "students disproportionately chose to write less challenging programs than their interest patterns had suggested". She felt that "many students would choose easy programs that happen to contain other interesting factors".

In March 2014's "Assessment and Evaluation in Higher Education", Felton and Mitchell claim (providing some evidence) that "Faculty who lighten workloads and inflate grades buy high SET [Student Evaluation of Teaching] ratings and popularity for their courses". Older staff are less prone to doing this.

The more a topic's taught, the more students will learn

In "When do students learn? Investigating factors in introductory courses" (Journal of computing in small colleges, 2012) it said - "we found that instructional time spent on a topic often has a far weaker connection to student learning levels than does instructor emphasis. ... Just spending more classroom teaching time on a concept will not improve student learning as much as an instructor placing greater emphasis on that concept ... For CS1, there were few topics for which there were statistically significant correlations between instructional time and student learning".

The better the teacher's presentation, the more the students learn

In the May 2013 issue of "Psychonomic Bulletin and Review" it reported that "When a presenter is seen to handle complicated information effortlessly, students sense wrongly that they too have acquired a firm grasp of the material". They're more confident, but perform no better.

In "The Times Higher" (30/5/13, p.7) it's reported that "lecture fluency did not significantly affect the amount of information learnt".

Clarity is good

In The secret life of fluency Daniel Oppenheimer wrote that for some exercises, "participants were significantly more likely to detect the error when the question was written in a difficult-to-read font. This suggests that they were adopting a more systematic processing method and attending more carefully to the details of the question".

Monday, 30 December 2013

Supporting LaTeX

When I began working in a university, part of my job was supporting a group who used LaTeX. They used Unix systems, and I maintained LaTeX on them. Installing could sometimes be a slog - fonts were a hassle, and packages kept appearing and re-appearing with inter-dependencies. I produced some handouts to help people with LaTeX. LaTeX2e appeared, which helped.

Time passed. The web was invented, so I put the handouts online, first as postscript docs, then PDF, then HTML/MathML. A web search for Tim Love LaTeX reveals that those docs have been widely copied. Documents like The Not So Short Introduction to LaTeX2e by Tobias Oetiker et al, LaTeX for Complete Novices by Nicola L.C. Talbot and Using Imported Graphics in LaTeX and pdfLaTeX by Keith Reckdahl have taken away the need for books, though the TeX Book is still useful.

As Word improved, LaTeX use seemed to recede, recovering as Linux appeared, LaTeX distributions became more stable, and cross-platform front ends like Kile and Texmaker were developed. pdfLaTeX became the predominant latex processor, DVI files becoming a rarity. As web pages grew in sophistication, LaTeX->HTML convertors became less fashionable (I used to generate PDF and HTML files from LaTeX masters, but tend to maintain the files separately now). The LaTeX page in our help system grew. I started giving talks on LaTeX for beginners and for report writers. Some staff made their undergraduate students learn LaTeX.

The CTAN sites became more comprehensive. A searchable catalogue appeared. Usenet newsgroups became Web forums, and sites like latex-community and tex-latex stackexchange attracted beginners and experts.

The LaTeX community has always been mutually-supportive and widely dispersed. Local support is much less necessary than it used to be, but sometimes it helps provide continuity. A Ph.D student who'd been to my talks and had read my handouts produced a class to support local thesis writers and left it with me when he left. It proved popular - our 3rd most popular help-system page. Another student who'd been to a talk improved the class in 2013 - it's available via our help system.

Thursday, 19 December 2013

Space, time, and C++ source code

In "Scientific American", December 2013, it said of reading texts in general that "When we read, we construct a mental representation of the text that is similar to the mental maps we create of terrain and indoor spaces". Students new to programming may have trouble when facing source code if they create inappropriate maps. I think that the more linear (more like prose) the code is, the easier it is for these students to understand. If execution starts at the top of the file, and ends at the end, so much the better.

Some deviations from linearity are fairly easy for beginners to understand because they're like those used in prose. Difficulties arise when the same part of text is executed multiple times, and/or when there isn't 1-to-1 mapping between the script and behaviour. In one exercise that we give students, we provide the source code of a function to simulate rolling a single dice - int RollDie() - and ask them to write a routine to simulate rolling 2 dice for a board game. Rather than write a function that returns RollDie() + RollDie(), some students create 2 copies of RollDie(), calling them RollDie1() and RollDie2(), then write a function that returns RollDie1() + RollDie2(), so that the conceptual 1-to-1 mapping is preserved. In this case, the fact that real world objects are being simulated may complicate the picture, but using rather more abstract maths proofs as a model introduces other misunderstandings.

In this article I'll consider how some features of C++ hinder the type of mental representation that students are used to. Conceptually, the text of a program is more like assembly instructions for flat-pack furniture than a novel. I'll also point out how some analogies to illustrate how languages work don't help - maths in particular can be a "false friend".

Loops

Small loops aren't too hard to understand - a temporary eddy in essentially linear code

while loops are more linear than for loops. In a while loop the lines that are repeatedly run are contiguous and in order; control takes only one step back.

In a for loop, the locus of control passes through the terminating condition, the body of the code, then back to the last statement, then back again, to the terminating condition before executing the body code again

Functions

As far as locus of control is concerned, simple functions aren't too bad. They're rather like footnotes - you jump to them and jump back again, carrying on from where you left off. Conceptually you can in-line them. Recursion is more complicated - essentially, multiple copies of the recursing code have to be imagined if the one-to-one correspondence between text and action is to be retained.

False friends - maths and time

  • After
    int y=2;
    int x=y*3;
    y=4;
    
    what value has x? People familiar with maths might give the answer 12, because they treat x=y*3 as a symbolic assignment, x being re-evaluated whenever needed.
  • In a maths proof, variables are usually symbolic, and at any time can have any value. In contrast, variables in languages like C++ always have a particular value. In
    int i=0;
    while (i<3) {
      cout << i;
      i++;
    }
    
    the single textual i variable in the expression i<3 has successively the values 0, 1, 2 and 3. The value changes in a way that the value of maths variables don't. The text in a proof is usually processed linearly - a particular i always means the same thing. Exceptions are in "proof by cases" where the reasoning branches (the "4-color problem" was solved using such a proof - a computer program), and "proof by induction".

Discontinuities

The distance between a language and its meaning is emphasised when a small change in the language can greatly change behaviour (and vice versa). C++ has several problems of this nature.

  • int x[12];
    
    creates an array of integers whereas
    x[12];
    
    doesn't create an array. It refers to a single element in an array, one which isn't in the array created using int x[12];.
  • The following loop
    int i=0;
    while  (i<3) {
      cout << i;
      i++;
    }
    
    terminates, whereas the similar
    int i=0;
    while  (i<3); {
      cout << i;
      i++;
    }
    
    runs forever.
  • The lines
    char   c='0';
    int    i=0;
    string s="0";
    
    produce variables that all look exactly the same when printed using cout, though they're not the same at all.
  • The lines
    if (x < 4)
    
    and
    if (x << 4)
    
    do different things. The meaning of "<<" depends on context - here it bitshifts but with cout it does something different. It never means "a lot less than".

Conclusions

  • Introduce students to while loops before for loops.
  • The use of flowcharts might help students who are processing the source code as if it were prose. Alternatively, it might help to use a debugger as a code-animator - see below
  • Code-folding editors are useful - they offer a way to make existing code into a "black-box" once it's stable, so that students don't become distracted by verbose detail.
  • Avoid recursion
  • If the meaning of something depends on context, the students need to be able to identify the limits of that context
  • Be prepared to introduce the idea of idioms. If you're learning English, then analysing the phrase "It is raining" down to the word-level is unhelpful - "what does it refer to?" is a linguistics question. Similarly, breaking down something like
       while(fileInput >> str) {
           cout << str ;  
       }
    
    into its constituent parts can easily be overdone by beginners who've been told to analyse, but haven't been told when to stop - "what is inside an ifstream"? They do need to know that it reads successive words from a file into the string called str until there are no more words left.

Monday, 20 August 2012

Making Programming Easier for Beginners

Introduction

In the days when home computers had BASIC it was common for bright children to write little programs - egg-timers, etc. They gained experience of programming as a concept, but just as importantly they got practise at making mistakes and fixing them.

In the Windows/Mac era this option was no longer available. Some of the older lecturers here say they have noticed a consequent reduction in programming skills amongst our new students.

It's been suggested that the Raspberry Pi might be used as a way to encourage entry-level home programming in the future. And perhaps schools might deliver more programmers to universities. But for now we have to cope with a significant minority of students arriving without programming skills. This leads to student anxiety when they're at their most vulnerable, poor end-of-year results, and perhaps an under-use of computing in their career.

In this document I consider the factors involved with these difficulties. The problem goes beyond being purely cognitive. Some students seem to acquire something like a phobia about the subject (not helped by the public perception of Computing being a male, nerdy, obsessive topic).

Attempted solutions aim to

  • Develop programming skills (or aid the transfer of other skills)
  • Reduce the anxiety levels associated with the topic thus aiding the learning process.
  • Identify the students who'd most gain from extra help once term starts.

What is hard about computing

Computing languages are unlike anything else that students are likely to have done. They're not even like maths. Compilers are unforgiving - always criticising and never praising. Students' programming skills span a wider range than that of any other examined skill, so non-programmers will feel stupid right from the start. Comments similar to the following are common - "It's too hard"; "It's too easy"; "Other people find it easy. Why do I find it so hard?"; "If it mattered we'd have been taught it already"; "arbitrary rules, it's all about jumping through hoops".

It may be that we're trying to teach topics that are known to be difficult but that only a few students will ever need. We teach a compiled language (C++) though few student will use one. Speed of execution is rarely a critical factor in student programs, but a significant factor in our choice of language.

People know which topics students find difficult. It's less clear how to exploit this knowledge. In "When do students learn? Investigating factors in introductory courses" ("JCSC", 2012) it said "we found that instructional time spent on a topic often has a far weaker connection to student learning levels than does instructor emphasis. ... Just spending more classroom teaching time on a concept will not improve student learning as much as an instructor placing greater emphasis on that concept ... For CS1, there were few topics for which there were statistically significant correlations between instructional time and student learning. ... Interestingly, three topics, control structures, subroutines/functions, and types, had weakly negative correlations."

Easing the Learning Curves

One can broadly categorize the problem areas as follows - Algorithms (What to do), Implementation (How to do it) and Psychology (Finding a congenial context within which to learn). Each category has a learning curve that can be made more shallow. Each has been targeted by educationalists

Algorithms

The idea of planning for eventualities that might occur during the planners' absence is not a scenario that students have much experience in. Also programming involves much more failure (error messages) than success, which distresses beginners. Solutions to these difficulties include getting students to

  • begin solely with algorithms - flowcharts, paper exercises involving recipes, etc
  • begin with easier algorithms - "Add 2 numbers"; "Write a times table". These tasks are boring but at least they let students focus on the implementation.

Implementation

  • Re-order the topics (e.g. delay the introduction of functions, Object-Orientation etc.)
  • Expand the documentation at the start of the course - offer cribsheets, etc.
  • Change the language
  • Write tools targeted to help the student with specific, known problem areas (we've written animations and teaching aids - e.g. 'for' loop help
  • Use a new language just for the start of the course - Interpreted languages help accelerate the edit-run cycle, reducing the psychological consequences of errors.
    Some sites use Scratch to narrow the gap between algorithms and implementation - the programs are flowcharts. One paper reported that "not only did Scratch excite students at a critical time (i.e., their first foray into computer science), it also familiarized the inexperienced among the with fundamentals of programming without the distraction of syntax".
    Jonathan D. Blake wrote that "Research has shown that assignments that provide early feedback and early success (and that are compelling and visual) are important in improving not just retention, but also gender equity" ((JCSC 26, 6, p.126). Languages like Turtle Graphics make feedback more visual (especially if they use robots - students can then see the physical consequences of their work).

Psychology

  • Computer-based Teaching - a supportive development environment can be developed (one that attempts to diagnose errors, for example). But this is likely to be language-specific and expensive to produce
  • More Interesting algorithms - If the task is interesting enough, students will be more stubborn when dealing with implementation issues. Students' supposed interest in computer games has been used to incite interest. Lisa Torrey "concluded that the most important interest factors were graphics, usefulness and entertainment value".
  • Working in Teams - This might help some to learning without exposing their ignorance to staff. Some students like to be taught via the language of their peers. However, the results are patchy and over-praised by students. Also, girls get a lot more help than boys.
  • Offer a choice of slow and fast courses, or easy and hard questions, or extra help. Lisa Torrey found that given a choice, "students disproportionately chose to write less challenging programs than their interest patterns had suggested". She felt that "many students would choose easy programs that happen to contain other interesting factors" ("Student interest and choice in programming assignments", JCSC 26, 6)
    Extra help can be made available
    • Making help available by phone or e-mail, or having a drop-in surgery
    • Offering 1-to-1 tuition
    • Online self-help (or supervised) groups (could offer marks for the quality of involvement; could use Skype).

See Also

Tuesday, 14 August 2012

Using Scratch to prepare students for programming

Scratch, first launched in 2005, is considered one of the best languages for introducing children to programming. Some universities are beginning to introduce Scratch into introductory courses.

Scratch

Scratch programs are flowcharts that the programmer constructs by dragging blocks around the screen. The blocks are shaped so that they click together if the "syntax" is correct. It lacks methods (functions), so it doesn't use parameters or return values, but it does have Events and Threads, both of which are important in modern computing.

Extensions to Scratch exist that add functions, etc - see for example Build Your Own Blocks. Scratch 2.0 is beginning to be used - it has procedures, webcam support, Lego support and even support for cloud programming.

Harvard

Harvard tried Scratch in a "Harvard Summer School's Computer Science S-1: Great Ideas in Computer Science", the summer-time version of an introductory course at Harvard College. Details are at http://cs.harvard.edu/malan/publications/fp079-malan.pdf. They used Scratch to introduce the idea of programming and set some exercises before moving on to Java - "Though some students spent only 2 or 3 hours on their first problem set, others spent upwards of 20, implementing projects more advanced than any of those written in lecture." One student wrote "Though I did not yet know how to create a for loop, I knew when a for loop was necessary because I had used loops in my Scratch program."

Encouraged by this, the staff introduced Scratch on the full undergraduate course. CS50 is Harvard College's introductory course for majors and non-majors. Typical enrollment is 300 students. Scratch is used in the first two lectures and the first assignment; the rest of the course is taught in C, PHP, and JavaScript. Details are on http://infoscratch.media.mit.edu/SIGCSE2010Workshop

Documention and initial Scratch code is available. See SCRATCH for Budding Computer Scientists (a tutorial).

Berkeley

In 2009 Berkerley trialed a course based on Scratch which they later introduced in an alternative introductory computing course. http://www.eecs.berkeley.edu/news/cso.pdf describes the reasoning behind the course changes, noting that

  • Scratch supports some advanced (Web 2.0) ideas. It allows students to upload their finished graphical programs to the web which can then be run online in a web browser, downloaded, modified (or, "re-mixed") and re-uploaded.
  • Scratch encourages broader participation - the report gives statistics on female and hispanic participation. They write that "We have a longstanding goal to provide alternative paths to prepare students for CS61a. The traditional path to CS61a, of taking the AP computer science test, suffers from little participation by populations that are typically under-represented in computer science."

Wisconsin

Their notes are at http://pages.cs.wisc.edu/~dusseau/Classes/CS202-F11/. The weekly exercises for this course are online - e.g.

  • week 1 - exploring the Scratch website, playing a game and answering a survey
  • week 2 - "this homework has two parts. In Part A, you'll use Scratch to draw an interesting picture. In Part B, you'll analyze different scripts written in Scratch and decide if they have the same functionality or not."

This course develops the social networking aspect. One of the first tasks the students are asked to do is upload a photo of themselves.

Rutgers

Their Programming for the Masses course uses Scratch. Though it's not a programming course, students do learn to write short programs. One development of this is the Scratchable Devices project where students can program their household devices. Using devices are equipped with an XBee module connected to Arduino microcontrollers, they can switch lights off and on by clapping, etc.

Ohio State University

In an Outreach course they offer some partly working scratch files ("Save the Turtle", etc) and invite the student to modify them. Their document is worth reading for the exercise - http://www.cse.ohio-state.edu/~paolo/outreach/ScratchSE/LabOverview.doc

Kent State University

Their introduction to computer science uses Scratch then JavaScript. Few details are online - http://www.cs.kent.edu/~volkert/10051/

Conclusions

Pros

  • Reputable universities have already done a lot of the work that we'd need to do. Proposals for course-changes, Scratch tutorials and exercises for students are all online.
  • Some students have an impoverished mental representation of programs - they don't "chunk". Scratch programs match my internal representation of simple programs - objects are nearly independent and have dynamic internal structure.
  • Though not many Universities are officially using Scratch, the more advanced school and OutReach exercises offer sufficient challenges for students-to-be. See for example NeboMusic Polygon Robot exercise

Cons

  • Scratch leads more naturally to Object-orientation, a trend that some universities have been distancing themselves from. Moreover, it segues poorly into initial C++ exercises like "get the user to type 2 numbers in. Display the sum" or "print the 5 times table"
  • Scratch bypasses most of the language features that C++ students find most difficult.
  • Quite a lot of the excitement of using Scratch is the social-network aspect, but this needs some management

Wednesday, 13 July 2011

C++ function problems

This page shows some of the students' imaginative attempts at solving one part of the 1st year Michaelmas computing course. The task is one that's been on the course for years, but this year we spoonfed them less. The students would have the same difficulties in many other languages, though C++ provides rather more challenges than Matlab (for example) would.

How we introduce functions

We explain functions gradually, using a mixture of explanation and practical work. The explanations include animations, diagrams showing functions as boxes with inputs and outputs, and sections entitled

We tell then that they have to do 3 things when writing functions: write a prototype, write the function, and call the function. The practical work begins with a gentle learning curve as follows

  • We show them is_even (a function that determines whether an integer is even) and give them a program that uses the function to see which integers in the range 1 to 10 are even. Then we ask them to produce a similar program to identify multiples of 3. This requires them to modify the code trivially, but we insist that they change the name of the routine (so they have to change the call and prototype too).
  • We get them to write a times-table program using a timesby7 function that we provide (the program will be similar to the above program)
  • We get them to write a program with just a main function, then get them to restructure it without changing its output so that it has main and another function.
  • Then we get them to write bigger programs with functions written from scratch
  • Then we get them to use library functions.
Common problems include
  • Thinking that the prototype
         int fun(int number);
    
    means that they have to call fun with a parameter called "number". We could get them to write the prototype as
         int fun(int);
    
    but that's not considered good style
  • Thinking that the prototype
         
         int fun(int number);
    
    calls the routine. We could ask them to prove to us that it does - by adding a cout call to the function.
  • Thinking that if a function prints out the answer, that's the same as returning it.

Playing with dice

About half way through their Michaelmas term work when they've already used functions we give the 1st years the following code

int RollDie()
{
   int randomNumber, die;

   randomNumber = random();
   die = 1 + (randomNumber % 6);
   return die;
}
We say

Each time the function random() is called, it will return a random positive integer. Work out what the ... function does and how it works.


One student didn't know how to search for "%" on a web-page, hence couldn't find where we'd described what the "%" operator did. I worry about students' webskills sometimes.

Then later in the handout we say

You've already seen the RollDie function that simulates the rolling of a single die. Copy it into your new file. Now write a function called Roll2Dice to simulate the rolling of 2 dice (call RollDie twice and return the sum of the answers). Before going any further, test it. If it doesn't work, neither will your full program! Here's a main function you could use

  int main() {
     srandom(time(0));
     cout << "Roll2Dice returns "  << Roll2Dice()  << endl;
  }
You'll need to add prototypes for RollDie and Roll2Dice too.


This task contrasts with last year's work where after we gave them the code for RollDie() we gave them the code for a routine with the prototype int RollManyDice(int M) (though we didn't provide the prototype or the final return ... line of the function). We made the change because we'd rather students programmed something simple themselves than merely type in more complex code than they don't understand.

Here's a list of solutions that students have tried

  1. Several start by writing this prototype
       bool Roll2Dice()
    
    because the first function introduced to them returns a bool.
  2. A few start by writing this prototype
       int Roll2Dice(int RollDie(),int RollDie() )
    
    because RollDie is "needed" by Roll2Dice, I presume.
  3. Some do this
    int Roll2Dice()
    {
       int randomNumber, die;
    
       randomNumber = random();
       die = 1 + (randomNumber % 12);
       return die;
    }
    
    (returning an integer from 1 to 12) or this
    int Roll2Dice()
    {
       int randomNumber, die;
    
       randomNumber = random();
       die = 2 + (randomNumber % 11);
       return die;
    }
    
    (returning an integer in the range 2 to 12, all the outcomes equally likely) or this
    int Roll2Dice()
    {
       int randomNumber, die;
    
       randomNumber = random();
       die = 1 + (randomNumber % 6);
       return 2*die;
    }
    
    (i.e. rolling a die and doubling the outcome). I think these examples illustrate that common sense suffers when students are struggling with C++.
  4. Quite a few people start by writing a new function to simulate the 2nd die.
    int RollDie2()
    {
       int randomNumber2, die2;
    
       randomNumber2 = random();
       die2 = 1 + (randomNumber2 % 6);
       return die2;
    }
    

    Some then try doing

      int total=die+die2;
    
    later in their program rather than calling the functions, not realising that die (in RollDie) and die2 (in RollDie2) are unavailable. At this point some students create global variables die and die2 while still creating the local instances of die and die2 - which silences the compiler but isn't the correct solution.

    Others write a Roll2Dice() function that calls RollDie() and RollDie2() to get the correct answer. Perhaps the existence of 2 dice makes them think they need 2 functions - I suspect they wouldn't write 2 functions to calculate the square roots of 2 numbers, or write 10 functions to roll 10 dice.

  5. The next is one of the most common solution, not calling the provided RollDie function at all.
    int Roll2Dice()
    {
       int randomNumber, die, randomNumber2, die2;
    
       randomNumber = random();
       die = 1 + (randomNumber % 6);
       randomNumber2 = random();
       die2 = 1 + (randomNumber2 % 6);
    
       return die+die2;
    }
    

Conclusions

I was hoping for
   int Roll2Dice() {
   int die1=RollDie();
   int die2=RollDie();
   int sum=die1+die2;
   return sum;
}
or even just
  int Roll2Dice() {
  return RollDie() + RollDie();
}

It's easy enough in a handout to explain how to write correct code, but this year we didn't want to tell them exactly what to type. Just about everything that we didn't dictate to them produced errors that revealed a lack of understanding. I think it would be counter-productive to anticipate and correct these misunderstandings by putting a list of what not to do in the handout - it would confuse them. Besides, it's useful to have these conceptual errors exposed as early as possible as long as demonstrator help is available.

Some of the solutions above are correct and the students often understand what they've written, so there's a case for letting them get on with it, but they're going to have bigger problems later if these conceptual hurdles aren't tackled now. (I once looked at a IIB project student's final program. It barely used functions. By factorising repeated code I reduced the line-count to 30% of the original. Worrying).

Some students are clearly just guessing as they go along, looking for any lines of code that look as if it should be copied. It would help if they revised earlier work, or trace their finger along the locus of control, explaining it line-by-line. Others start with a reasonable idea of what to do but make small mistakes that lead to bigger ones as they try to silence the compiler at all costs. It would help if they could identify run-time errors as soon as possible, but iterative development is something they only slowly learn, and besides, not all of them know what results to expect.

Understanding functions remains a problem. We introduce functions by analogy with mathematical functions, but in C++ they can see inside the black-box that is the function, and once they do, they find it hard to treat the function like a black-box ever again (it becomes a physical thing occupying space, rather than a concept). As an educational aid it helps to have an editor that collapses functions.

Frequencies

We get the students to run routines like Roll2Dice() and record the outcomes. They find

   int outcome=Roll2Dice();
   frequency[outcome]=frequency[outcome]+1;

hard to understand, which isn't so surprising given that after 6 hours of practicals

  • a few students still don't know how to add 1 to a simple variable.
  • more than a few students have "no idea" how to write a line that "creates an array called frequency big enough to store 6 integers". I left one such student to read the documentation for a few minutes, but when I returned to him he was none the wiser. The Arrays section of the doc might be sub-optimal, but it can't be that bad - it's much the same as last year's.
Even those who do understand arrays have trouble with the code quoted above, though they're happy with
   int outcome=Roll2Dice();
   if(outcome==1)
      frequency[1]=frequency[1]+1;
   if(outcome==2)
      frequency[2]=frequency[2]+1;
   ...
I've tried to spell out a 2-page explanation of the shorter version as a Frequently Asked Question but some people don't understand that either. When the penny drops they sometimes remark "that's clever". Then they try to be too clever and do
    frequency[Roll2Dice()]=frequency[Roll2Dice()]+1;

wondering why it fails (they're calling Roll2Dice twice, so the RHS and LHS may refer to different array elements). Having fixed it they put the line in a loop. A few students do this

int tries=0;
while(tries<100) {
   int outcome=Roll2Dice();
   frequency[outcome]=frequency[outcome]+1;
   frequency[outcome]=0;
   tries=tries+1;
}

Why is frequency[outcome]=0; there? Well, one student said that it was in an earlier loop so they thought they'd better put it in this loop too.

In short, there are still many indications that a non-trivial minority of students are just fumbling blindly through. If anything, the changes to the course this year make it easier for demonstrators to identify the students with severe problems - it's harder for students to bluff their way through.

According to "Validating an instructor rating scale for the difficulty of CS1 test items in C++" (Lulis and Freedman, JCSC 27, 2 (December 2011)) "faculty members disagree amongst themselves as to the difficulty level of questions involving functions", much more so than for questions involving other topics.