My overall thesis for the course: the choice of (or design of) programming languages matters in more than a superficial way.
Different languages are designed with different problems in mind: they are (of course) often very good at those things. Good languages are good at other things too.
Hopefully, learning a couple of new languages helped you look at programming problems differently. The overall approach to solving problems in different languages will force you to approach a problem from another perspective.
When encountering a new language in the future, try to learn the ways that language likes to solve problems. Use them: don't just keep writing C++/Java/C# with a different language's syntax.
Consider this possible lesson from the course: learning a new programming language isn't that big a deal, and can improve your programming skill overall.
The languages we have discussed so far have been general-purpose programming languages:
Domain-Specific Languages (or DSLs) are langauges designed to solve a particuar kind of problem(s), and likely not others.
When doing a lot of work in a specific problem domain, a general purpose language can be too general. If you are always doing a few very specific things, it would be nice to have a language designed just for that.
Some examples you may have encountered:
DSLs may or may not be
programming languages. Other possible results: documents, 3D models, animations, computer chips, ….
Using DSLs can be wonderful (if they do the job you need) or a mess (if they do most of it).
Problems that can be solved with a DSL can also be solved with a general-purpose language. Maybe you should use one instead?
Good: A general-purpose language is more flexible and can (nicely) solve other problems you encounter.
Bad: It might not be as good at solving the specific problem you're working on most of the time, or it might be harder to approach those problems.
One solution is to use a general-purpose language and a library that is good at solving the problem you have.
A big library can start to feel like a DSL: the code you write in your (general-purpose) programming language can start to use the library almost everywhere and look very different.
maingeneral purpose language) that builds a configuration object, instead of a separate configuration file.
Some example code in R vs Python+Pandas that both read a CSV file and do a least-squares best linear fit:
data <- read.csv(file="data.csv", head=TRUE) summary(data) fit <- lm(data$y ~ data$x) fit
import pandas as pd from scipy.stats import linregress data = pd.read_csv('data.csv') print(data.describe()) fit = linregress(data['x'], data['y']) print(fit)
In some cases, the DSL is simply the better tool for the job.
In others, a general-purpose language and good library will be much better.
Opinion: I'm rarely completely happy when working with a DSL. The limitations are eventually going to be a problem. Sometimes, the DSL is the least-worst option.
Maybe choice of programming language doesn't matter?
All general-purpose programming languages are Turing complete: they all can/can't compute the same things. Clever compiler writers can make code in any language execute fast (except when they can't).
We have seen that it's possible to write imperative code in Haskell (sort of, with monads). It's possible to write very functional-looking code in any language (e.g.
itertools from Python).
In either case, you have to have some idea what's actually happening when your code runs, so you don't write inefficient code.
Library writers are starting to realize that the same problems can be solved in any language. A library (especially one that starts to feel like a DSL) could implement the same API in multiple languages.
Then the programmer's choice of language really doesn't matter very much.
There are several multi-language APIs…
pars = document.getElementsByTagName("p") new_em = document.createElement("em") new_em.appendChild(document.createTextNode("some text")) pars.item(0).appendChild(new_em)
e.g. Spark for big data analysis. This is Scala but could also be Python (or with some syntax changes, Java or R):
df = spark.read.option("header", true).csv("books.csv") df = df.select("title", "author") df = df.groupBy("author").count() df.write.csv("author_counts.csv")
A few more…
These cross-language APIs are much more the exception than the rule, but they show that library design can sometimes be more important to a programmer than the underlying language.
The choice of language is (in my mind) basically about three things: writing correct code; writing it quickly; having it execute quickly.
We have seen various ways that tradeoffs could be made:
If there was a
right way to choose a language, there wouldn't be so many options.
There are projects where the language choice matters a lot. There are ones where the choice of library matters more.
The way you make the various tradeoffs will depend on the project and the programmer(s).
Sometimes programming languages are important.
Sometimes they aren't.