Learn C, Then Learn Computer Science
qrohlf.com
qrohlf.com
I say this as someone who watched the catastrophic results of trying to use C++ as a language to teach data structures. It is far more important to be able to think abstractly than to know how to deal with pointers.
High level languages tend to favor one data structure over another. Starting with those languages can give students the "hammer syndrome" w.r.t. that structure.
As for preferring one data structure over another, C does that as well: arrays are the only data structure with first-class support.
I've heard this claim many, many times, but for me, I find Scheme (and Haskell, for that matter) impossible to work with. I love what Scheme and Haskell do in theory, but in practice, I find them unusable for those things.
With Scheme and Haskell, I find I'm always trying to figure out how I should make the compiler happy, vs. taking an abstract concept that I understand well and just implementing it, which is something I find easy to do with C.
But I also suck at math, and my assumption is that for people who don't suck at math, Haskell and Scheme and all the others are probably easier, and that makes sense to me.
Modula-2 and Oberon are also quite small.
Why is it important to teach the underlying mechanics of a computer in a data structures course, or an algorithms course, or really anything beyond OS or computer architecture courses (and perhaps a compilers course)? The reality is that the way computers work "under the hood" is counterintuitive in an extreme sense. Pointers are a counterintuitive abstraction. Fixed-width arithmetic is counterintuitive, as is having integer division always round down, as is using floating pointer numbers to represent fractions. Yes, eventually a CS student should learn about these things -- but an introductory course is the wrong place, as is basically anything that deals with purely abstract notions (data structures, algorithms, cryptography, etc.).
"...an introductory course is the wrong place"
I'm glad we're in agreement.
Any course on crypto needs to address both algorithms in the abstract and the particularities of how they're implemented in the real world.
I disagree. There is a rich theory of cryptography that is entirely abstract, for which the low-level details are an irrelevant distraction. Even the AES finalists, which were designed with low-level concerns in mind, are described abstractly and can be implemented at a high level (I have an implementation of Serpent in Common Lisp, for example -- no messing around with low-level details, just a functionally correct block cipher). Within the crypto research community there are people who work on high-level languages suitable for cryptography implementation:
http://www.charm-crypto.com/Main.html
To be fair, there is also an enormous body of work on implementing cryptosystems in the real world -- at least enough to have an entire course dedicated to the topic. If anything, we should really have two courses: an introductory course that covers the theory of cryptography, and a cryptography engineering course that deals with real-world implementations.
Specially if buffer exploits and pointer misuses are to be taken into account.
I'd say this is an extremely important part of a data structures course.
Say we have an array of integers and a linked list of integers. Which will take less time to iterate through? We all know it's the array, but you have to be aware of how caching works to know that that's the case. Which takes less space in memory? Again, we know it's the array, but you have to understand pointers to know why that's the case. If you only know what a linked list is in the abstract, then you'll have a hard time reasoning about space usage when compared to an array.
These are just a few examples, but there are countless more. It's hard to reason about how the different data structures work in the real world if you don't know how the computer works.
> The reality is that the way computers work "under the hood" is counterintuitive in an extreme sense.
Since when was CS about teaching only what's intuitive?
Unfortunately at some point, teaching OOP became all the rage in schools, and so C++ is chosen instead. That's a mistake, Java or C# should be used for teaching OOP, C should be used to teach data structures and at least some algorithms. Without hands on memory allocation, you're not really getting a full understanding of how data structures work.
I bought into this previously after hearing it constantly repeated, but don't anymore. Your point about OOP is fair, but I think there is a sane subset of C++ that is incredibly useful for teaching new programmers. One thing to be avoided is needless OOP hierarchies. User-defined types are an incredibly powerful abstraction, and makes certain programming tasks look and feel extremely natural. If you listen to Stroustrup talk about C++, this is what he tends to highlights about C++, not the advanced features. Those can come later.
C++ has plenty of warts, and I dislike certain parts of it as much as its detractors, but C++ is still an awesome language.
For me C was just one year transition between Turbo Pascal and C++, back in the mid-90's. Only used it for university assigments and on my first job. Otherwise when the option is reduced to C vs C++, I always pick C++.
For me, C was too litle when comparing with what Turbo Pascal offered me. Luckly I discovered C++ shortly after learning C.
In my experience TAing an undergrad course that used C++, almost all of the things that left students scratching their heads were things that are present in C. No garbage collector, no built-in way to determine array sizes at runtime, no way to determine if a pointer has already been deallocated, no requirement that non-void functions actually return a value on all control paths, etc. The worst thing C++ does is to amplify these problems (particularly that last one -- yes, I know, use -Wall, but someone who is just starting to use a language would not know that, and having to teach compiler flags is an even worse distraction from the subject matter of the course).
Really the problem is not language size at all. Python is a big language too, but it does not have the above problems. Common Lisp is just as big as C++ (in terms of the number of pages in the standard), yet these are not problems Lispers have. Scheme is a small language, like C, yet the elegance and expressive power of Scheme is on a completely different level from C.
The problem is that the few abstractions C presents are hard to deal with, especially for beginners, and the abstractions that C could present are sorely missed. Even the abstractions C presents are unreliable, with loads of undefined behavior and plenty of ways to break the abstractions.
Really, the fact that real-world C programmers have to pick a subset of the language and enforce various style standards and coding conventions speaks volumes about the suitability of C for beginners. If we were going to require students to use a specific subset of C, why not just write a compiler for that subset and use that to teach? The answer is pretty clear: if we were going to write a compiler for a new language that was suitable for teaching students, we would write something better. Why bother when we already have better languages to choose from? Save C for the OS course, and only as long as it remains relevant there.
The undefined behaviour is particularly bad. Its hard to tell if a wrong result is coming from a wrong algorithm or from some undefined behaviour that is silently messing up your results and this only serves to confuse students. Its also a PITA to debuig segfaults - even just getting a stack trace means that you need to use a separate debugger tool.
Another thing you didn't mention about the garbage collection is that it makes it much harder to do string handling. For example, the simple task of reading a name from standard input has multiple solutions and but all the simple ones (scanf and gets) are potentially dangerous. And this is not counting the off-by one erros in allocation because of forgetting to account for the null terminator.
Frankly, almost none of the C++11 features are actually useful for teaching data structures, and those that are relevant would only confuse students. Basically, only auto and the three kinds of smart pointers are relevant to an introductory data structures course. At the end of the day those would only create as many problems as they solve. For example, unique_ptr means that there is only one "owner," right? Wrong, get() returns a raw pointer to the object, and you can make a new unique_ptr from that. Sure it is easy to avoid -- if you are an expert with lots of C++ experience, who follows coding guidelines and all that. The data structures students had little to no C++ experience and would almost certainly have done what I just described -- and that is just one of many ways they can and will screw up C++11 features.
At the end of the day, C++ is too complicated, too poorly defined, and has all the wrong abstractions for basic CS courses.
How do you teach a basic data structure course in Python?
Pascal seems like a much better choice for data structures than C or C++. Or you can use Scala and teach functional data structures if you're adventurous ...
Then why are you teaching C++ like you are teaching C?
Use clang ?
root@iwfvm02086 ~/temp/c_test # cat test.c
#include <stdio.h>
int a_func(int a_bool)
{
if( a_bool )
{
printf("Passed variable was true\n");
}
else
{
printf("Passed variable was false\n");
return 0;
}
}
int main()
{
int num = a_func(0);
printf("In main : num = %d\n",num);
}
root@iwfvm02086 ~/temp/c_test # g++ test.c -o test
root@iwfvm02086 ~/temp/c_test # ./test
Passed variable was false
In main : num = 0
root@iwfvm02086 ~/temp/c_test # clang++ test.c -o test
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
test.c:14:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
1 warning generated.
root@iwfvm02086 ~/temp/c_test # g++ --version
g++ (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
root@iwfvm02086 ~/temp/c_test # clang++ --version
clang version 2.8 (branches/release_28)
Target: x86_64-redhat-linux-gnu
Thread model: posix
Really, the fact that real-world C programmers have to pick a subset of the language and enforce various style standards and coding conventions speaks volumes about the suitability of C for beginnersI am confused; all languages used in real world need this. Can you elaborate which languages are used in real-world that does not require coding standards ?
No garbage collector, no built-in way to determine array sizes at runtime, no way to determine if a pointer has already been deallocated
These are also side-effects for having the advantages you have teaching C for a Computer Science and Engineering course. Once you understand the fetch-decode-execute model of how a computer essentially works, it is a simple step from there to C.
I agree that, higher level concepts like Algorithms, Neural Networks are better taught with a higher level language.
eyeroll
I would recommend a language like Python, where simple data structures like lists and dictionaries can be created on a whim, freeing up students to tackle more fun problems.
Classes at the time were a mix of C, Pascal, and Lisp (at my school, YMMV). Certainly all the chances for getting pointers wrong made developing in C harder, at first. Even today I prefer to reach to Python to throw together some algorithm I am musing about. So I definitely acknowledge your point.
But, I just don't see a way around it. Today I am refactoring code to make it stay in the cache better. Doing that is not an exercise in pointless efficiency; it is the difference between the program being usable or not (it is a real time system). I contemplated compiling to assembly and eyeballing it, but a few sessions with the profiler got me the answers I needed. But to do this I had to keep in mind the pipeline architecture (cost of if statements if you don't get the branch prediction), the size of the cache, the cost of function calls, etc.
I recognize there are careers out there where you never have to touch that stuff. You write SQL calls and use a 4GL language, and so on. But what happens when your SQL runs to slow? Do you randomly vary the various server settings until it seems to run better, or do you actually understand (say) the cost/benefit of making the cache for the indexes larger? How would you talk to a piece of hardware your boss drops in your office? How..., well, you get the idea.
None of that is advocating building an entire 4 year curriculum solely on C/C++. Certainly it makes sense to do the algorithms class largely in a language like Lisp or Python. But after a certain point if you want real performance you are in C, battling low level details, and I think that is as important, if not more important, than proving the O() complexity of Fibonacci heaps.
In my experience, learning how the computer worked made it easier for me to learn to program it. My wife, was much more an algorithmic thinker and could care less if this variable was in a register or not, and focused on how things flowed through the program. I think they are both valid approaches.
i know a whole bunch of people are going to argue pro specialization, but i think we need to rethink the way we teach. we've built efficient workhorse factories which we call universities, and some of the top tier ones are slowly moving away from that system.
there are also a lot of known cases where crossdomain talent has brought a perspective which led to a whole bunch of problem solving. but i'm careful with conclusions here, because we know correlation does not imply causality.
we're not teaching people, we're indoctrinating them, to a point where your sound reasoning is valueless, because you don't have a ph.d in the domain you talk about. what's tested in your university exams is not whether you're good at something, it's how good we can recite the things that have been taught to us. it's a system that carries from primary school to everything else.
somewhat related is also this gem, someone posted on hn before http://pauli.uni-muenster.de/~munsteg/arnold.html
EDIT: you might wonder how that is related. one example: i struggled during the universities architectural classes. even though having grown up reading intel platform references and looking at disassembled c/c++ and delphi code i understood memory layouts, threading, pipelining much better than anyone else in the class. i also spent a lot of time learning basic mips architectures.
the problem was that none of that really helped me to do well on the exams. the reasoning behind it, is that class is structure in a way so that once you learn the theory behind it, you'll have a reference point once you actually need to do something in that domain. that reasoning is in fact sound, but only if we assume that no one actually knows what they want to do.
> In my experience, learning how the computer worked made it easier for me to learn to program it
yes, but the question is, do you need university to tell you that?
> yes, but the question is, do you need university to tell you that?
Of course not, anyone can tell you that. But knowing who told you what you know, sometimes helps a third party evaluate your statements of knowledge :-)For limited ranges of valid. If you are implementing a low performance requirement CRUD app, certainly you can become an effective programmer without knowing the low level details.
But if you want to be an engineer? Good luck. I've worked with people that didn't know the stuff behind C, and they are pretty useless as soon as performance matters, or you need to talk to hardware, or crank through a lot of numerical computations, minimize watt usage of a cellphone, app, debug complicated situations, and so on. They don't have a good mental model of the machine in their mind, and so they cannot figure out what is going on, reason about the performance of a modern chip, and so on.
There are a lot of arguments for expediency on HN. Probably it is partially justified, but I will always advocate for an engineering education, as opposed to a 'learn rails in 3 weeks and get a job' approach. Education and knowledge enables you to tackle any problem that comes your way.
So, while you can learn to be an effective debugger of a Python script (say) and so on without detailed knowledge of the machine, mastering the fundamentals will make you an effective debugger and enable you to do so much more. To stick with the python, what happens if the python implementation is buggy? There is a large subset of programmers that can not cope with that situation.
Why limit yourself? If this is going to be your career, the way you pay your mortgage, feed your kids, and so on, invest in yourself. I'm having trouble of thinking of the downside of acquiring the knowledge, but I can trivially think of the upside.
The world needs people who think mechanically as well as people who think at a very high level of abstraction. I'm glad people like you exist, as tech would be vastly behind where it is now otherwise. I'm also glad there are people like me. We may not always see problems the same way, but the world is a better place because of our differences.
I'd be willing to bet that the people that came up with software transactional memory were comfortable in C and assembly as well as Haskell, and hadn't bottlenecked themselves with the false dichotomy of thinking functionally vs thinking imperatively.
The world needs people who think mechanically AND at a high level of abstraction at at the same time.
Learn Delphi/Object Pascal, Ada, Modula-2, Rust and discover control over memory managerment doesn't require throwing safety out of the window. Performance can be fine-tuned to the 1% hotspots that really require playing dirty tricks.
That there are modular systems programming languages with compile times times that leave C to shame.
Then cry as you are forced to adopt C to be understood by the rest of the world.
[I'm a veteran of a ton of Object Pascal, btw. Done some Delphi, too -- it was nice. But.]
In general, pushing a niche language as The One does not do a beginner a service. Delphi has never been more than a niche.
We had a guy at Apple decide to do his project in Oberon. Super smart guy who pretty good work. He wound up getting fired because it wasn't a smart choice for the people around him who had to take over the code.
I don't know why some people over-index on programming language. You use what's appropriate. If you're working alone, do whatever floats your boat. If you're on a team, using the Latest Shiny Thing or The Most Correct Safest Thing may not be the best choice. If you're a student, using your professor's favorite language (we used to call these little pet horrors PL/Prof or PROF-TRAN) outside of the course is probably a bad choice -- you want to learn what the market is, and you need to know what the weak points of your chosen language are.
It's particularly poignant to see "Java only" kids come out of school who are utterly ignorant of memory models, barely know what XOR is, and who can only express themselves in terms of classes and interfaces. There's more to life than that.
Sure, it is all about learning for the job I guess.
My rant goes into another direction actually.
Young kinds nowadays tend to think that not only C is the only player on its field, it never existed nothing else before it.
Whereas many of us, remember the days when C was just another systems programming languages among many others to choose from.
So if they learn only C, then they get into this mentalit that bounds checkings, modules, proper vectors belongs to the realm of VM languages, while only C allow for full control.
If on the other hand they learn about the Algol family of systems programming languages, besides C, they will be aware of other languages that offer the same feature set of C, compile to native code as well, while offering higher productivity.
Having that knowledge will make them better C programmers as well, as they might learn a better sense of safety and disciple while coding C.
It's pretty excellent for learning how to implement a simple language in C.
http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf
Also a nice way to learn about bootstraping compilers.
Generating code code for another OS without Scheme support is just a matter of having your compiler cross-compile to the other OS. Then use the fresh backed compiler to re-compile your compiler in the new OS.
Not massive by any means, but the C standard library does include qsort() (quicksort) in stdlib.h
In the high school computer science courses I was able to take, the programs were relatively simple with an, in my opinion, too-overt emphasis on object oriented programming. It was in java, and very little of the class focused on the "how" aspect of the language.
My first CS courses at university were in Ada. I don't know how many of y'all have programmed in Ada, but I think about it like a wordier C that doesn't let you just get away with shit because it's strongly typed. This was the language we were taught basic control structures in and, to be fair, the way we were taught focused on good styling so that our code would be unreadable mush.
The UNIX class was in C, and it is, in my opinion, the most rigorous course that most of the students will take on their way to the bachelor's degree. The students build, across a series of projects, a shell that can execute commands and run simple scripts. The sorts of problems encountered introduce the students to the nature of C at a very low level, as well as the sorts of structures that can be used to solve practical problems.
Many of the high level more theoretical classes are language-agnostic, and many of the students use either Python or C#. I think that it's good that these higher-level theoretical classes allow us to choose our own language, because I think that the ways in which different programmers attack the same problem might bias them towards one or another language.
Recently, the lower-level classes had their programming language changed. Heeding the argument that Ada wasn't super relevant in the higher-level classes, the faculty changed the language to Python. This was, I think, a mistake. My opinion is that the lower level classes should be taught in C for many of the same reasons Rohlf mentioned. I think it's important that the students have an idea of how their data is being represented on the disk so that they could better understand the costs associated with certain tasks.
The best argument that I heard for Python was that not everybody taking these into classes go on to write the sort of code that requires something fast or efficient. Python makes data processing easy, which is really the most important thing that students should learn in intro-to-programming classes. I'd say this is a fair point.
I taught myself TI-Basic in the 7th grade. Then when I was really fluent in it and started hitting its limits around the 9th grade (I was mostly interesting in writing real time games), I picked up z80 assembly. Later (10th grade) I wanted to write programs on my computer, I installed Linux and learned C (not that they're related, but the hacker world really intrigued me. It also means that I spent my first "real" programming years as a member of the broad Linux community; I even submitted patches to large FOSS projects like Gnome, which still shapes me as an engineer to this day).
Then in university we used Ada for algorithms/application programming the first semester (partly because I'm French, and French professors love the fact that Ada is French; and partly for the reasons parent poster mentioned), before transitioning to C (at first for Unix programming, and then more general programming), and finally doing C++/Java in our final year (we also had a few domain specific classes where we used a different language: SQL for databases, assembly for electrical engineering, PHP for webdev, etc.).
I really like the progression I followed, as I feel like it was logically consistent, exposed me to a lot of different aspects of computer science, and forged me into a fairly solid programmer. I've tutored students whose first language was Java, and their mental model of programming/computer science was a big mess. The best of them figured things out a year or so in, but a lot of them remained confused throughout their college years.
Now I volunteer with a program that teaches kids how to program, and we use Ruby. I think Ruby/Python are great for giving beginners a taste of programming; and it's enough for the kids who don't fall in love with it. But with the kids for whom programming just clicks and is clearly going to be their field of predilection as a teenarger/college student, I'm starting to believe that C (ideally on an Unix system) is the way to go.
They are already exposed to it by making use of Python/Ruby.
I appreciate C, but wish I learned more high level languages to be more prepared come graduation. C is important to know, but it can also be overemphasized in some colleges.
It's a shame it's so damn verbose. A fortnight ago I was trying to brainstorm how I could put a tighter syntax on it, possibly with some kind of pre-processor. Ideas welcome!
When a big part of your job is to read the code from others of various skill levels, one learns to have a soft spot for verbosity.
More words do not necessarily lead to clearer, more understandable code.
The last team I was on held regular classes on F#, I'm sad the team got disbanded before I picked up a significant chunk of the language.
I would start people off programming at a higher level of abstraction and once they can do that dive into how things work. You could start the other way but it may be too theoretical and discouraging.
Pascal used to be the language of choice and IMO can still work well. Things got more complicated when we got all those competing paradigms and now you have a matrix of language/paradigm. Should you teach OO? Functional? Procedural?
I also think it's important to lay our some theoretical foundations as you're teaching the first language. You don't want to overdo it but you need to start building some basic ideas, notations, concepts. As long as it doesn't get in people's way in their ability to actually build something...
If you want to understand how computers work there's no substitute for programming in assembler, preferably, under different hardware architectures.
This debate about how to teach programming/CS/software engineering is endless. Different people and different schools have different goals and different capabilities. A well rounded software engineer definitely needs to have a good mix of theory and practice. A CS researcher needs a different perhaps mix.
As a teenager, I picked up a book on C++ having already learned BASIC, Pascal, and MS-DOS but never got proficient in it. I should have picked C. The "++" lead me to believe that it was a better language than C and I didn't have any real programmers around to tell me otherwise.
Oh the missed opportunities...
Sounds like C++ and you didn't quite work out. I'd still encourage trying to figure out how some pieces of C++ can improve your C code and use those. You're welcome to stick to C in the rest of your code. A lot of "real programmers" do use C++ successfully and a lot of software you use has C++ in it's DNA...
EDIT: (That said I would only expose new students to C++ after they've seen C and some higher level language so they can appreciate the niche that it fills)
I will probably never touch C++ again. I solve all my problems with Ruby and if I ever need to go lower-level, I'll break out C and maybe Lua.
Back when I was getting into 'serious' coding, anybody with experience in both C and C++, whether they liked one or the other better, could have told me enough to make me realize I was better off learning C first.
[1] http://www.drdobbs.com/open-source/interview-with-ken-thomps...
I am a real programmer, with almost 20 years experience.
I'll take C++ over C without thinking twice about it.
I first learned Pascal and was very relieved to move to C. I don't think such limited languages are good for much of anything. They just frustrate users.
I don't know Python but from what I know of it it seems like it would be a fine first language too. Anything else I know of seems like it has significantly wose issues than C IMO.
It looks like you learned standard Pascal, instead of the many dialects that were way better than C.
Harvard (who sends a lot of people on to PhDs) forces everyone to learn C in introductory cs50. I like how they do it. If you don't get "the machine" early it is hard to get it later.
I still think I have to polish up on 'em:
#include <stdio.h>
#include <ctype.h>
//
int chk_arg(char *s, int (*f)(int)) {
while(*s)
if(!(f(*s)))
return 1;
else
++s;
return 0;
}
//
char *s[]= { "1048leet576", "numbers only pls\n" };
if(chk_arg(*s, isdigit))
printf(*(s+1));
> This was confusing - my classmates were juniors and seniors who were 3+ years into a computer science degree, yet many of them didn’t seem to have an understanding of how computers worked. They could write high-level code and analyze algorithms, but had never used malloc.What the hell, CS students who haven't used malloc? I've got no formal background in CS, yesterday I wrote a binary search tree in C that passed valgrind.
I get the impression it is the same situation in the UK. It's nice knowing I can do a dozen rounds with a CS graduate.
When I took my degree in Portugal in the mid-90's, it was a 5 year long degree, with heavy mix of theory and practical subjects in lots of programming languages.
I got to use C, C++, Prolog, Camllight, Java, PL/I, Algol, Pascal as compulsory ones. Plus many many others that I got to learn/use as part of the compiler design lectures I used to attend to.
All CS areas had introductory levels as compulsory, with the more advanced ones as optional subjects. Given the way the credits were set up, quite a few of those advanced ones were also required.
I say learn assembly first, then learn C.
Then do whatever you want.
1) Computer Science, which is, in my opinion, entirely a subset of mathematics, and should be taught as such.
2) Coding, which is the ability to break a problem down and describe it in a series of simple steps.
3) Craft and application, which is everything about how to use tools, best practices for code architecture, and everything else that every new graduate is usually terrible at.
I think we could satisfy most of the world's need for "programmers" by teaching #2 and #3 in a trade school model.
Incidentally, I think #1 could easily be taught without #3 at all. I get the impression that there are quite a few academic people who tinker with interesting algorithmic work, in esoteric languages, who couldn't effectively write maintainable code for mass deployment. Not that there's anything wrong with that, it's just a different area of specialization.
* Turing machine -- just the tape and making it do the equivalent of procedures so that we can compose things. Brainfuck is a valid homework medium.
* A relevant ISA such as ARM -- We can let Thumb/2 be bonus points, but the real goal is just to convey that ISA's are usually written to take the most generally abstractable things you would do with a Turing machine and do it more succinctly and faster in hardware.
* Build a function stack with the goal of understanding how procedures become generalized by calling conventions or optimized by inlining. The lesson is that we stay pure for flexibility and get dirty for raw speed.
* Introduce Scheme and tail recursion optimization. Now the whole of functional programming and the abstractions -- and their optimizations -- are opened up with a firm footing in the machine.
Turing and Church probably did write most of CS, so it's obvious that you want to relate the two to create the most generally useful bridge concepts for the rest of the long life of a programmer, that if they never let up, will inevitably touch both high-level and low-level languages.
OS's are the final frontier here, but cannot possibly be squeezed down due to things like MMU functionality totally clouding up what is what. Making a machine look like it belongs to the program is what OS's are good at, and this is a different kind of abstraction to grok than the relationship between the machine and the programmer.
I just had no interest in coding. (Or math for that matter, though ironically, I also read math books.)
Anyway, I've always wondered if I'm a better or worse CTO for having taken that route. I do know I code much less than my peers, even though (it seems to me) I get much better results with far less coding effort.
Here's an example of where I think learning CS, then programming, helped.
I had written my own JavaScript application framework, called Blossom[0], and I wanted "real physics". I took a look at the various 2D physics ports that had been made to JavaScript, and they all had pretty bad performance. Also, I knew from my work as a filmmaker that "real physics" is actually a pain in the ass, because what you actually want is directable physics that feel real. (Stick with me, I'm getting there...)
So, I took a step back and determined that what I wanted was to be able to use tween curves like normal, but have the actual path that was taken depend on the velocity and/or acceleration of the movement when the user released their finger, yet be "directed" according to the tween curve.
That required doing math, specifically, getting first and second derivatives from your tween curves. Yuck. Except, CS to the rescue, there are these things called Dual numbers[1], and when you use them, you get automatic differentiation[2] for free, without having to rewrite your code.
So I wrote a Dual number implementation for JavaScript, grabbed a JS parser and rewrote the tween functions at load time (i.e. with code, automatically) to use the Dual numbers so that I could extract the velocity and acceleration. I then took the original curve based on the user's movement, blended it with the tween derivatives, and the resulting animations were actually really great. The whole thing was efficient enough to get real time performance on an iPad 3 in mobile Safari, entirely in JavaScript.
And the total time from start of work to the physics-based Dual-number tween animations in Blossom? Two days, and about 2K LOC.
If I hadn't know about Dual numbers, there's no way I'd have gotten there just by sitting down and programming, and who knows how long it took the FB team to do the dynamics for FB Home, or the Apple team to add UI Dynamics to iOS 7. My guess is that it took longer than two days...
[0] https://github.com/erichocean/blossom
I think the most useful class I took that explained this (in my sophomore year) was a class on digital logic and micro-architecture. Just about every school I know teaches some class like this early on in your education (at least teaching the basics -- gates, latches, flip-flops, adders, etc.) In mine, it even carried up through some basic assembly code. This class gave me enough to know how computers are working at a fundamental level to be able to use that to my advantage when implementing projects.
Lastly -- you're getting a CS degree, not a programming degree from a vocational school. Does everyone who researches... quantum computing, or natural language processing, or graph theory have to know and communicate in C? I think there are other pursuits beyond programming that you get from a CS degree, and to say it's necessary to learn C pivots your school closer to a vocational school. Not that that's bad -- it's just different than what you signed up for.
Taken as a sum of collective knowledge, I think everyone is right in this case. I think the general idea people are trying to get at is this: 1. To work in technology, you must love learning. (Don't get steamrolled). 2. To work in technology, you should know how computers really work. (Learn about C.) 3. Working in technology is not about learning where to but the curly brackets. It's about learning how to think logically. (Learn Computer Science.)
In this sense, I think a great way to get started is by working on a project that you love and in a medium you love. Then as you start hitting limits, descend to C and learn algorithms.
With UNIXs spread into the enterprise, C started to gain weight.
If UNIX hadn't been successful, it would just be yet another language.
It just seems like all the issues talked about were computer science issues.
Abstract vs. Concrete Data Types are introduced very early as representations for the theoretical structures discussed in class and then we are given projects that can be solved using concepts and theorems introduced with the expectation that we will implement the appropriate structures and algorithms in C. The code itself is read over carefully and just as important as whether the output is good. Now, this is partially a luxury afforded by my university's small size; freshman and sophomore CS classes aren't taught in 200 person lecture halls, they're 30-40 students at the max. My first exposure to a linked list was writing one in C, not using one in Lisp. You model them, write proofs, recurrence relations, graphs, etc. on exams, and implement them in projects so that you show an aptitude for both the theory and the mechanics.
By the time you hit your fourth year, you take Programming Languages and Theory of Computation. Automata/Machines, Grammars, BNF, Compilers, etc. in lecture; seeing these concepts applied by studying and writing code in OO languages, LISPs, and Prologs in lab. And you'd sure as hell better understand how the garbage collector in your favorite high level language works or you'll get hosed on the exam. There's other staples mixed in of course; a whole semester devoted to Java/OO (I think a whole semester devoted to functional programming and Lisp would be better, but that's another story). A semester of OS, a semester of Networking. But just focusing on the whole programming/vs science side of it, there's no reason they can't both be taught effectively.
When a language like Pascal is taught as a first language students can focus on the mechanics of their algorithms rather than struggling with language oddities and machine architecture. I think that's important for new programmers to be able to focus on the flow and mechanics without worrying about other details. Once you get that you can "advance" to things that leak more of the underlying architecture into your program. There are probably many other languages that fit that bill.
EDIT (replying to jkrems): E.g. in C if(a=1) assigns 1 to a. I think some modern compilers at least warn on this but they didn't use to and it's perfectly legal. You can't do this in Pascal. You can still make a mistake but you'll get a compiler error. This is a very common mistake for beginners...
[1] http://www.eis.mdx.ac.uk/research/PhDArea/saeed/paper1.pdf
- pure mathematical stuff, graphs and such, you can skip programming
- making algorithms/protocols/etc by simple models require to understand what a computer can do, etc so learn at least Python
- making new architectures, efficient functions (like for crypto), go to C.
I am suggesting Python, because it is probably the simplest programming language to learn.
I'm not saying that learning Python when you do purely theoretical stuff is useless, just that you can skip it and still work. Event if you do no CS-related things, programming is useful.
tl;dr: go for Python, unless you need to now the specific workings of a computer
https://en.wikipedia.org/wiki/Scheme_%28programming_language...
(Otherwise I agree, start with something like this to learn CS)
This was back in the early 90's. When I go to college, I was able to opt out of the first couple of intro CS classes (and get credit for them) by taking a test or two.
This is a good course about architecture http://www.nand2tetris.org/course.php
This is likely to be horrible advice. I don't doubt that there are good C tutorials on youtube, but there are probably also hundreds of extremely poor tutorials that are seductive and even highly rated because the people rating don't know better.
K&R C is excellent. I don't like overbearing advice, but "Every serious programmer should read K&R C" isn't bad as far as such advice goes.
I don't particularly like the "Learn X The Hard Way" series (maybe it is the right way, but I find it too painful), but there is Learn C The Hard Way [0].
I'm at exercise 19 and enjoy it so far. I think I already learned a lot. It may not suite everybody and I don't even know if it's good, though.
EDIT: WOW. I'm amazed at how many people think that C is "how memory works". Just wow. This is one of those things where you're confusing the map for the territory and ascribing value to something because its "hard". C is a fairly high level abstraction for interacting with a computer...i know that everyone has heard that c is close to being assembler...but what you are forgetting is that assembler is also an abstraction over operands. The reason i think its important to point this out is that malloc and free arent magical. Othér techniques are just as valid and the notion of "low level" is misleading. C makes tradeoffs that actually give rise to all of the vulnerabilities and stability problems in all the software that you have ever used. Those tradeoffs are REAL and just because lots of you get this macho nonsense about not using safe collection types everyone on the planet has to deal with malware. So many of you buy your own bullshit at an astonishing level...its really breathtaking to see how many of you cant see the built in assumptions in what you are saying.
malloc and free aren't even a part of C itself. Other than static (globals and "static" the keyword) and automatic (stack) allocation there isn't any memory management in C itself. malloc and free are library functions wrapping system calls. That's something to do with the operating system - the machine itself has NOTHING like malloc and free.
I and many people know C but know fuck all about assembly programming. (for now)
I know gcc provides them for you if you don't specify the right includes, but that's gcc, like.
I think I'm going to go on considering them not technically part of C itself, until I have more information.
Thanks.
Like I said, before a compiler can be certified ANSI C, it must provide the Standard C Library (for whatever platform the compiler is for). As a programmer, you don't have to use the supplied functions, but they are there, and they do comprise a part of the C Standard. And because the functions are defined, the compiler writer can do some pretty neat things.
For instance, include string.h, and that informs the compiler you want to use the string and memory functions defined by the C Standard. The compiler can then generate code directly for, say, memcpy() instead of generating a call to said function (it can inline it, even though C89 made no standard method of inlining a function). Or the function sin() if you include math.h (some CPUs support a single instruction for the sin function). Don't include string.h, and well ... what happens is up to the compiler. Most just give a warning about an undefined function, assume it's defined as "int unknownfunction()" and leave it up to the link phase to either find it or not.
Yes, there is a distinction between the C language, and the C library, but both must be provided if a C compiler wants to conform to the C Standard.
ufo got my point. the modern microprocessor is vastly different than the view of the world that is exposed through C. The fact that C still works is more of a testament to hardware designers than it is something "intrinsically true" about C and its design decisions.
Let's get away from subjective "shoulds" and talk about practical stuff. You want to learn things, as much as possible, that (a) are likely to remain useful in 15 years and (b) are going to qualify you for the highest quality of jobs.
C, as a language, passes this test. So do the fundamentals of computer science; they may not bring you quantity in job opportunities, but they'll give you access to quality. Aside from that? Well, it's hard to predict the future. I can't make individual calls. Who would have thought JavaScript would be so popular in 2014? The whole language is a hack. But if you learned it in 2000, you still have a high-demand skill set.
Learning one thing or one small set of things won't do, though. You need to future-proof yourself with a wider knowledge portfolio, and very few jobs will teach a person to do that.
On the other hand, if you learn a lot of useless and parochial crap that won't generalize (i.e. the quirks of your own corporate codebase) you get to a semi-depressed state of "learnout" (you struggle to assimilate new things, because you've filled your brain with unrewarding crap) and that's no good either.
Interesting enough that it is a must for the web development although it's lacking the structure definition from CS point of view.
How about other scripting languages, such as Python or Ruby?
Ruby is harder to predict. It seems like a lot of the web developers who would have used Rails a few years ago are now opting for server-side javascript, based in node.js.