I have been a professional programmer for several decades working in various languages, but my original degree was in electrical engineering. That course involved some programming (BASIC and Pascal), but that was more about getting results than studying the principles of programming in general. To try and remedy this I am doing some on-line courses. These are on Coursera and my employer is paying for them. There is a yearly fee for which you can take as many courses as you like. I have done some on specific aspects of Python, but the latest is just called Programming Languages A. It is the first of three related courses.
The instructor is Dan Grossman from the University of Washington. He obviously knows his stuff, but I have a minor technical criticism that his audio is slightly distorted all through the course. The slides he uses are from 2013, but the material is still relevant.
You might expect a course like this to use one of the propular languages such as Python or Java, but he opts for ML (Meta Language). which I would call a more purist language. I recently took a look at Lisp and ML seems to have some features in common with that in the way the code is structured and its use of lists. We actually used the SML (Standard ML) variant.
I had not heard of ML, but I quite like it now. That said, I might not use it for general programming tasks that Python may handle better, but I could apply what I have learnt to other languages.
Some features of the language that are used in the course are:
- Static types. You cannot change use a variable that has been set as an integer in a context that needs a string.
- Immutable values. Stored values cannot be changed, or at least they should not generally. There are ways to work around this when required.
- Type inference. The language can work out what type a variable has to be, e.g. if used in arithmetic it has to be a number or if list operations are used then it must be a list. Variables can be 'polymorthic' in that it may be possible to pass different types of value to a function, but they may need to be consistent in relation to other values.
- Minimising side effects. Calling a function should just return a value without affecting other parts of the software.
- Recursion. Functions can call themselves.
- First class functions. Functions can be passed as parameters to other functions.
Excuse me if I am mangling terms, but I am still new to some of the concepts and terminology.
Here are some code examples:
fun fact (x) = if x = 1 then 1 else x * fact (x-1) fun swap (x,y) = (y,x) fun count xs = case xs of  => 0 | x::xs' => 1 + count xs'
The first is the standard factorial function using recursion. In the whole course we did not use any of the regular loop structures that are commonly used in other languages. With recursion you need some way to exit and this does so when the counter reaches 1.
The second is a simple polymorphic function that swaps a pair of values around. It does not matter what the types of those values are. You can specify types in function definitions, but rarely have to unless you need to limit them.
The third function counts the items in a list. The case statement is powerful as it can match against patterns as well as values. The pattern x::xs' gives you the first item of the list as x and the remainder as xs'. You can define your own types that can hold different sorts of values then use this pattern matching to determine which you have in that instance.
That count function does not need to be written as it is part of the standard library along with lots of others, but it is useful to write functions like this yourself to learn the language.
The coursework consisted of some programming challenges to solve. You were given a script to test some values, but the grading was more intensive to catch edge cases. I found it challenging in some cases. There were one or two that I really struggled with and I dropped a few marks. There was a peer-review process where other students would look at your code to ensure you were using the sort of coding that had been requested as you could get the same results using functions that were not taught on the course and some approaches could be less efficient.
Another interesting aspect of the course was the use of the Emacs editor. This is quite popular in some fields of IT, but I had hardly used it. I can see it is very powerful even though I only used some basic functionality. One useful feature was the ability to run ML code within the editor. Making the most of it involves learning lots of key commands.
Although I found it hard work I did enjoy the course and will be continuing with part B, which uses the Racket language. That is another I have not heard of before. It is being used as an example of a dynamic typing language. The third part uses Ruby to demonstract object-oriented programming. I have heard of Ruby, but not used it.
These are not course to do if you just want to write a web app or a mobile game, but I think learning such fundamental aspects of programming helps you do a better job.