For a beginner, is it better to start with C or a higher level language?

Some friends of mine, over the years, asked me suggestions on what to study for learning how to code. Most of them had no real final purpose, just wanted to be able to understand programming and be able to work with it if needed.

When the asker was a motivated person, I always answered to first learn C, then C++ and finally to pick up an high level language (like Python, R, MATLAB, Swift, JavaScript or whatever then would have been needed). This is the road I followed and I feel that having first learned a low level language (with pointers!) followed by its natural OOP extension, I have now a deeper control on how a generic programming language behave, and I can easily learn any programming language sharing the paradigms of C++.

On the other hand I suggested less motivated person to start with an high level language (Python, R or MATLAB), so to not let them be scared by the pitfalls of C.

Based on your experience, would you give the same suggestion I gave? I mean, do you agree that starting with C/C++ is beneficial for a deep understating of programming or do you think that is easier to start with a simple language and then deepen the knowledge with C/C++?

• I'll note that this question is also useful to instructors who are developing curriculum for novices. Apr 1 '18 at 12:50
• Possible duplicate of cseducators.stackexchange.com/questions/212/…
– Ben I.
Apr 1 '18 at 14:06
• High and low level are non-binary. Python, R etc are higher than C. C I just above assembler. Saying that C is high level, is out of date. Much like most curriculums. Apr 1 '18 at 22:00
• As somehow this is the big deterrent to learning lower level languages. I'd like to know who, teaching an introductory programming course, actually ends up in a place where their students actually need to learn memory management? Apr 4 '18 at 21:06
• I view this as separate from the possible dupes on the grounds that it's about giving direction to others on leaning programming. The answers do far seem to be, in the main, of reasonable quality with evidences to support the answer. It seems like a natural extension to this question. Apr 6 '18 at 0:08

Based on your history and preferences, you have a particular view about what it means to be a programmer. I have somewhat the same history, but come to a different conclusion. Start with a high level language, probably either a good OOP language (Java, Python, Scala...) or a good functional language (Scheme, Racket, ...). Those two groups of languages cover much, though not all, of the "higher level thinking" in programming today.

Programming Languages are all about abstraction. Different languages offer different kinds of abstractions and different levels of abstraction. However, once you choose a language, the programs that you build within that language are usually (always?) about creating even higher level abstractions than those in the base language. We try to write programs "in the language of the problem we are solving" and choose names (abstractions) accordingly. That is why we don't name our variables v1, v2, etc and our functions f1, f2, etc in our programs. Our variables are things like size and done and function names are like compute_capacity.

Every programmer needs to know something at least of a whole range of abstractions. Assembly language is very low, C is a bit higher. Ruby is quite high, as is Racket. Wherever you start learning you will eventually, after totally grokking that language, want to go to other levels. If you start at a low level then you have only one direction to move, but if you start at a higher level you can move both higher an lower. Thus you can learn how things are represented (at a low level) and how things might be hidden/regularized at a higher level.

Each programming language that you learn is built on a set of ideas that encapsulate what a program should look like. The view of a C program is very different from that of a Java program. The difficulty in moving upwards in the abstraction scale is that it is often difficult to give up the low-level constructs that you have become used to for others that are more appropriate in the new language. For example, polymorphism exists in most languages. In low level languages like C, the polymorphism is ad-hoc, implemented by setting and testing flags. In a higher level language (Java), polymorphism can be implemented more directly using certain design patterns (Strategy/Decorator) and helper objects. But the programs written by those who started low, too often still use only ad-hoc methods, which potentially leads to programs that are difficult to read and understand (too-deep nesting of structures).

You say you can learn any language using the "paradigms of C++". I know a few programmers who can validly say that, but most C++ programmers cannot, outside a fairly narrow range of languages. Moving from C++ to Scheme or Standard ML, for example, requires a completely new way of thinking about programs. Adopting this new way of thinking is actually inhibited by what you learned well in C++. Not that it is impossible, but it is a harder climb.

Let me give an analogy. If you want to become a medical doctor, you don't start by gathering herbs and chanting ancient songs. You don't, then, progress to leeches and bloodletting, following an historical trail. It is true, however, that some medical practice is only considered valid because it was handed down from antiquity but actually has no scientific basis. At some point in history, something was tried and it worked. No one knew why, but it became standard practice. But, and the point is, you don't need to start your medical training with ideas from 100 or 1000 years ago, even though many of the things learned then are still valid today. Nor do you need to start your education at a low level.

One misconception that people often have about high level languages is that they can only be understood in terms of some (supposed) implementation in a lower level language. Certainly compilers take this view, but humans don't need to. If a language is minimally useful it will provide a complete set of abstractions that permit you do any computation (Turing complete) solely within that set of abstractions. When I program in Java, I don't need to think about what the compiler will do with a reference variable (is it a pointer? is it like a pointer? is it completely different?). I just know that it gives me access to an object so that I can send messages to that object. I think in terms of reference and message, not in terms of pointer and function call and don't care if they are similar or distinct. In fact, thinking at the lower level can lead me astray. In a Java program, with overridden methods, it is not possible, in principle, to know which version of a method will be invoked without a complete trace of the program. You may not be able to discern the precise type of an object without that trace, and a distinct execution of the program may take a different path.

Some people think that low level languages are more efficient than high level languages. That may have been true at one time, but isn't necessarily true anymore. If you examine a few statements in a low level language, like C, they certainly seem to be easily implementable on a Von Neumann architecture. The problem is twofold. Programs consist of many many statements and it is easier to write and reason about complex algorithms in a high level language, especially one that is purpose built (bespoke) for that domain. Compilers today can execute tens of millions of instructions to globally optimize programs, something that a low level programmer can't do, and something that low level coding often inhibits. If I write a program describing explicitly how a problem is solved (typical in C), the optimizer is pretty much limited to following that instruction stream (not precisely, I realize, but that isn't global optimization). On the other hand, if a program describes what is to be accomplished rather than how to do it, an optimizer has many more options for coming up with both a high and low level set of strategies for execution.

The second reason that low level programs are only apparently efficient is that modern computers are only barely recognizable as Von Neumann architectures anymore. With multi-level cache (both data and instruction) and multi-processing on (say) graphics processors, the relation between the programmer notations (the program) and what is executed gets farther and farther apart as time goes on.

Summary:

2. A decent language will provide a (Turing) complete set of abstractions. Therefore you can think at that level of abstraction.

3. Lower level language are not, inherently, more efficient than higher level languages, though they may appear so. Compilers can do more than you think if you let them.

4. A human, moving to a new abstraction level, will have difficulties made more intense the more they are committed to the "old way of thinking".

5. Start somewhere. For myself (who started low), starting higher gives you a better, clearer path. But you will eventually want to branch out. Learn to think, completely, within the abstractions provided by the language you use. Understand those abstractions in terms of the other abstractions and idioms in that language, rather than by "mentally compiling" everything.

Here is an odd historical note about medicine, that I'm pretty sure doesn't really apply here:

In a few cases it isn't ethical anymore not to use some relatively ancient practice, so science is blocked from advancement in that area. The Pasteur Treatment for rabies is like that. It works, but is a dreadful process for the patient. But rabies is nearly always fatal, so it is unethical to set up a scientific experiment in which the control group gets Pasteur, but the experimental group gets (only) a vaccine.

• I trust that compute capacity does not return a value, but sets an instance variable. (or else is poorly abstracted). Wow this answer is double plus good. Apr 1 '18 at 22:47
• Don't think narrowly @ctrl-alt-delor. It needn't be either. It could set off a long chain fo messages that does interesting things in a database or over a network or readies the available weapons for the alien invasion, or ... There is more to life than getters and setters. Apr 1 '18 at 22:52
• say no to getters and setter, but yes to command query separation. Apr 1 '18 at 22:56
• There's often a confusion between learning comp. programming and learning the low level elements of a computer. Actually it more about learning to analyze what you want and figure how to have the bloody thing doing it with providing a description in whatever language you have. Apr 2 '18 at 17:43
• @Buffy, confronting manual optimizations with compiler optimizations is a false alternative, unless you write in asm. For JIT, I found this question, though it really refers only low-level optimizations. But I didn't find a good example of a global optimization that would be bound to high-level language. And actually, Prolog is my example of a language that looks like saying just what, but in practice says also big part of how.
– Frax
Apr 19 '18 at 9:30

Starting languages for non-programers

Vastly depending on what is the purpose, but for some people it may be beneficial to choose for a first language a scripting language, that is used only as snippets in a wider context. The main advantage is that you get useful stuff basically from the point zero, and not only after learning half a language. If you stop learning after 5 hours, you may still have some benefit from it.

Some possible choices:

• Bash

Obviously not for everyone, but very useful for Linux/Unix (Mac?) users managing any substantial amount of files. The main advantage is that the requirements to make it useful are very low, it's not like you need to learn half a language to write a "Hello World". It's just echo Hello, world, that's it.

• JavaScript

Somewhat peculiar language and hated by many, but it's again very easy to make it useful, and, importantly, everyone has it right in their web browser. You can start by adding one-line snippets to your static HTML-page to make it more fancy, install Tampermonkey and fix annoying UI on your favourite web page (disclaimer: be advised about security issues with installing userscripts from untrusted sources), or just tinker with browser console to see how different pages are built.

• Python/IPython (as a fancy calculator)

Just that. If you need to do some simple math or just want to quickly check how many digits does 17³³⁷ have, Python is your friend. Clean syntax and built-in support for bignums make it a perfect tool for your little arithmetics. After you choke your machine with computing 17**337**337, you may try to do something more ambitious.

• Octave/Matlab, R

Fancy calculators for people who don't think that "matrix" is just a movie title.

• PHP?

Yeah, that's an awful language for most uses, but if someone has an idea for a Personal Home Page with some simple interaction, it may be just the right tool to use.

Starting languages for wannabe-developers

Now, to the other question: "do you agree that starting with C/C++ is beneficial for a deep understating of programming"? Yes.

For a person planning to do any serious programming, I'd perhaps recommend starting with C++ (where "++" stands for "streams, strings, vectors and maps", maybe now also "smart pointers"; the rest is confusing and unnecessary noise) or Pascal/Delphi (that's what I actually started with) for less opportunities to shoot your feet, and a good GUI library with IDE support. It is also very useful to do some programming in a functional language (OCaml? Scheme?) early, to get some different perspective on programming, with better structured framing. I'm not sure it's a good first choice though.

However, I'd be careful to not go into too far into high-level programming in C++. C++ "high level" structures are actually thin wrappers around explicitly low-level stuff. To write classes and abstractions, take a proper high level language, perhaps Java or Scala. C++ is not a high level language, and I tend to treat it's high-level features as a kind of a last-resort: if you are bound to using C++ for performance and low level features, that is how you get some abstractions.

As for starting with higher-level languages, my intuition is that thinking about classes and this kind of abstraction is unnecessary noise at the entry level, which is why I look with great suspicion at starting with Java (in which even a "Hello world" is in a way OO). I don't have any data-backed point here though. Additionally, I find the Java memory model (i.e. references everywhere) to be both confusing and misleading.

• Being competent in C++, and starting with C++, are two very different stories. Sep 30 '19 at 7:44
• @MichelBillaud, of course they are different, but what is your point? I'm explicitly referring to the basic C++ here.
– Frax
Sep 30 '19 at 13:23
• what is 'Basic C++" ? C with classes? Sep 30 '19 at 16:29
• Not necessarily, though that depends on exact interest. If one wants to write GUI applications, some classes and OOP are unavoidable. However, one can start with just solving algorithmic problems, and for that classes (meaning: defining classes) aren't necessary or very useful. However, some STL classes are very handy and would be a pity not to use them.
– Frax
Sep 30 '19 at 22:34
• As I wrote in the answer, I don't think C++ is a good language for learning Object and Object Oriented programming, due to the implementation being much too sensitive to low-level details. It is good as being close-to-metal (and, more importantly, OS API and ABI) as C, yet with some handy abstractions and stronger typing that C lacks.
– Frax
Sep 30 '19 at 22:34

I have also followed a similar path in learning. I am also often asked where to start. My response has been to start with a language like Java. This is for very practical reasons from an educator's as well as a student's perspective.

1. Students appreciate being able to build or solve something quickly. As well as being able to grow with a language.

2. Teachers can spend a significant amount of time debugging student code. Finding bugs written in C/C++ by beginner programmers can be very time consuming, especially if it involves pointers.

3. It's useful to choose an environment that can run on a platform of the user's choice.

Java is close enough to C that transition to/from it is manageable, while being safer (no pointers) for people starting out. I also prefer a strongly typed language.

I will offer the following anecdote: This year I gave an assignment to my students to write a simple program in assembly language just to have an awareness and appreciation of the differences between low and high level languages. (Print out a number being incremented by 1 in a loop starting from 1 and going to 10.) The code for this in assembly was over 130 lines of code, while the corresponding Java code was a few lines.

This exercise was enough! to give them a deeper understanding of how a CPU executes code -- programming.

They liked learning about how registers and memory locations are used by CPUs. They came away with an understanding that a variable is really a named location in memory.

It should be noted that in some curricula students are expected to know the definition of high- and low- level languages with clear demarcation .

• Java is a complete mess (some types are objects and behave a certain way, others aren't; you are playing with pointers to the objects and nobody says so), and has lots of mysterious stuff for the beginner that makes no sense (class, ...). Better use a clean language like Python 3. Aug 3 '18 at 12:22

There isn't just one answer to this question. It depends entirely on what the person wants to learn. Somebody who wants to make video games should probably take a different path than somebody who wants to build a website for their home business, or somebody who wants to build an Android app.

But generally speaking, you should start with something engaging. I personally recommend starting with Processing. Processing is designed for novices, and makes it easy to create visual and interactive programs without a ton of boilerplate.

Processing is built on top of Java, but allows you to ignore a lot of the boilerplate until you really need it. It allows you to learn the fundamentals, then OOP, and allows you to "graduate" to other languages like Java or Javascript, or even C or C++ if you really need to.

See these related questions:

Modern C++ (i.e. C++11 and above) is hands down the best introduction to programming language. This is not only my opinion but what was realized after the "Java" generation graduated and went into the market.

To explain before I get the StackExchange record in negative votes:

1) Modern C++ does not require the use of pointers (unless of course you want to, which is not advisable in modern programming).

2) Modern C++ is a general language. You can go form low-level to high-level, use Objects or procedures. It is no longer the old C-like low-level language. You should not learn C before it either.

3) There was a time when many universities switched to Java as starting language because old-fashioned C was traumatizing. I like this quote from Joel Spolsky:

"All the kids who did great in high school writing pong games in BASIC for their Apple II would get to college, take CompSci-101, a data structures course, and when they hit the pointers business their brains would just totally explode, and the next thing you knew, they were majoring in Political Science because law school seemed like a better idea."

Today when I teach I tell my students a simple rule of thumb to distinguish modern C++ code from obsolete code practices: "if you see a '*' (naked pointer)in the code it is usually obsolete". (keeping in mind the context of this subject).

4) However, when that Java generation graduated the industry started to realize that they lack in relation to the feel and understanding of how computers work. There are few publications on the subject. And if you notice many have moved back from teaching Java as a starting language.

5) Modern C++ gives a wide range of options: from low-level to high-level programming concepts. From using procedural programming to OOP. (and no pointers) :-)

I suggest you check out the textbook by Gaddis and and one By Liang. These are my favorite ones on Introduction to programming and after.

• Comments are not for extended discussion; this conversation has been moved to chat. Apr 6 '18 at 6:33

I started low level, but I prefer to teach high level first. I have talked to a few teachers that like to start low-level, and decided that they are also correct. It depends on the teacher, and the students (not quantity of motivation, but type of motivation). Low-level, if you/the student likes/wants to study how the machine works (more machine focused); high-lever if you/the student likes/wants to focus on what a program does (more human focused, but not just interfacing to a human, it could, for example, also be controlling machinery). However I think that the middle path is less good. Therefore start low: A nice assembler (arm, 68000, 6502, little man), or start high (Eiffel).

I have also realised that most high level languages are not designed for teaching: For example

• the best order to teach the language, is not the best order to teach concepts.
• There are many nasty gotchas (C++ is an example with many of these).
• There is a mismatch between language and concepts. Many to many relation ship between language features, and programming concept (C++, java, C#).
• Much boiler plate needed in first lesson, that can not yet be taught (public static void main (string[] args))

I don't seem to have a problem with low-level ones. Though I no-longer see a need to use low-level languages. As Eiffel, Go and maybe others can do their job better, and as fast. The least troubling of the High-level languages seems to be Eiffel, but this is OO. So we need a good non-OO high-level language to teach first. I teach python, but I don't like it as a teaching language (it has a few problems).

Therefore High or Low? It depends, but avoid the treacherous middle.

I don't know what I would recommend but there are a few criterion I'd bear in mind if I were you.

1.) It's a lot harder for someone who's only been doing Java/C# (automatic memory management) vs. C/C++ (manual memory management).

2.) Some languages make creating certain data structures significantly more difficult. I'm thinking of BASIC--any sort of data structure involving a recursive definition (e. g. binary tree) is a lot harder to do with a language that doesn't support recursive types.

3.) I think I'm somewhat alone in this opinion but I'd say that learning OO is actually harder for those new to software development than is learning software development without it. So I'd tread lightly in terms of teaching a non-developer OO based languages.

4.) If you want something which gives quick feedback to the learners, a scripting language (or at least a language with some sort of REPL) is superior to a compiled language. The compile/link/run cycle will never be as quick as simply typing in an expression and seeing what it evaluates to.

5.) Are you concerned about variable typing (or conversely no typing)? Typing, like default immutability, can eliminate a whole class of errors all by itself but it can be hard for students to grasp--at least in my experience anyway.

Those are just a few of the criterion I'd consider. Again I may be alone in this opinion but I'd stay away from Javascript for teaching purposes. I say this for a few reasons; there's a ton of libraries for JS and they all work differently. Also a lot of JS is really hacky (I mean that in the pejorative sense).

Most of them had no real final purpose, just wanted to be able to understand programming and be able to work with it if needed.

It is much easier to maintain and grow such motivation for the subject if your students can quickly develop some programs they are proud to show.

As far as I see among my students, printing "Hello" 10 times, summing the elements of an array, or concatenating strings doesn't really fall in that category anymore. Funny examples come more quickly with higher level environments.

Once they've learnt the basics (variable, loops, problem decomposition) they can learn low-level things. Actually programming is not about using low-level devices, it is about learning to make things with what you have at hand.

I would agree with you (based on my experience): In BS, we took C in 1st semester, then OOP and Data Structures with C++ and gradually switched to C# and Java in later semesters.

I was one of the worst coders of the class and despite hating programming (to bits, in fact bytes) I found C# and Java pretty easy due to the effort poured in by our teachers in C and C++.

Similarly, in my pedagogical career, I have found two roadmaps:

1. C/C++ in PF, followed by either C# or Java (more frequent one)
2. Universities which start right from Java

I got a chance to teach Operating Systems to students of category 2 and needless to mention how badly they failed at comprehending basic system programs written in C++ (not even C). It took me more than 3 lectures to explain them only the syntax of pthread_create() since they had no background of pointers, function pointers and even passing by reference and how could they given they begun programming with Java.

Recently, I taught Introduction to Biological Computing and used Python in the course and that experience prompted me to think a bit about why not use it in PF for CS students, but No! This experiment, thankfully I stopped it before implementation. Obviously doing Python after C is very easy, but its not other way around. No wonder that as per TIOBE indexing, C language has made a whooping 6.62% growth in last 12 months. 1

Students need (a) motivation, and (b) a useful language.

For (a), use a high-level language, preferably one in which graphics is easy to handle, and cross-platform (yes, a few will be running Linux, mostly a motley of distributions/versions; most will swear by Windows of several batches; then there are Apple-lovers...). If they can build something fun in a few hours, that is more than enough motivation. Build some simple game, have them participate in some of the one-weekend game building competitions once they are further along.

For (b), today Python wins hands down: there are libraries for anything imaginable, and then some. Much "real work" in e.g. astronomy is herding a bunch of data-munging scripts (with FORTRAN or C++ backends) in ever changing combinations, orchestrated by Python. Much of the "user friendly system administration tools" in my Fedora system are written in Python with nice GUIs, and hand the grunt work to the traditional commands.

Check out some text like Think Python, there you'll see how far you can go in an introduction course.

I recommend Python. Why? Strong but dynamic typing. Strong resemblance to English. But.... it is a tool students never outgrow. C is tricky. You don't want students bogged down in understanding the heap when they are trying to master stuff like recursion, looping, conditional logic, and variables.

• Why does a beginner need to bother with the "heap" when learning recursion, looping, conditional logic, or variables? C can be tricky, but in a beginners course, it is certainly not. Apr 4 '18 at 20:38
• Once you want to create a large object such as a list or an array, you are into malloc/free and the heap. You don't stuff that big stuff onto the stack. Apr 4 '18 at 23:07
• Not all lists or arrays are large enough to require heap usage. For the purpose of a beginners course, you can certainly, as an instructor, ensure your students don't have to bother with this. Apr 10 '18 at 13:46

Define "beginner". A third grader who want to make a game? A high school student? A college grad looking for a new career? With out knowing that this question is unanswerable. I teach high school programming. When someone says "beginner" to me I suggest Kodu, Scratch or Small Basic. If someone wants to build a game then go for Gamemaker or Unity. Want to build an app then look at MIT AppInventor. These are starting points for beginners.

• The first day I started programming I was surely a beginner, I was 13, I started with C/C++ (I was using iostream, string and vector but it was basically C: no classes, only structs). Growing up I started appreciating the differences between C and C++ and refining the knowledge of both. I think there is no real need to start with something like “scratch”, unless someone is really young. Probably the best thing would be to start with scratch at, maybe, 3-6, and then gradually move to a real programming language. But i have no experience in that, only my personal one. Apr 6 '18 at 10:29
{"extraction_info": {"found_math": true, "script_math_tex": 0, "script_math_asciimath": 0, "math_annotations": 0, "math_alttext": 0, "mathml": 0, "mathjax_tag": 0, "mathjax_inline_tex": 0, "mathjax_display_tex": 0, "mathjax_asciimath": 1, "img_math": 0, "codecogs_latex": 0, "wp_latex": 0, "mimetex.cgi": 0, "/images/math/codecogs": 0, "mathtex.cgi": 0, "katex": 0, "math-container": 0, "wp-katex-eq": 0, "align": 0, "equation": 0, "x-ck12": 0, "texerror": 0, "math_score": 0.24572037160396576, "perplexity": 1268.017356847956}, "config": {"markdown_headings": false, "markdown_code": true, "boilerplate_config": {"ratio_threshold": 0.18, "absolute_threshold": 10, "end_threshold": 15, "enable": true}, "remove_buttons": true, "remove_image_figures": true, "remove_link_clusters": true, "table_config": {"min_rows": 2, "min_cols": 3, "format": "plain"}, "remove_chinese": true, "remove_edit_buttons": true, "extract_latex": true}, "warc_path": "s3://commoncrawl/crawl-data/CC-MAIN-2021-39/segments/1631780060677.55/warc/CC-MAIN-20210928092646-20210928122646-00160.warc.gz"}