A few thoughts on Programming languages

an image of Ferris, the mascot of the Rust language

Just a few thoughts on programming languages that have been rattling around in my head this week, but which don’t each merit a full blog post. The main theme is that the culture behind each programming language leads to some interesting choices, as is the case with spoken languages.

This week I started learning how to program in Rust. Even though I’m using the project-based Command-Line Rust to learn, the author still went with the traditional “Hello, world!” project for the first intro to the language. I was also working on a Go project last week and so it immediately stood out to me that (at least as taught by this author) Rust has the print! macro that allows you to succinctly print to the command line. By contrast, Go requires importing fmt before you can print. This was the first topic that was swirling around in my head this week. What makes language designers choose whether printing output (one of the most basic things a program can do) is built-in or requires an import. I even remember back when I was learning Java in undergrad (I think it was Java 1.8, but I don’t remember) we had to use the savitch library just to get program input (another very basic computer program concept). As I thought about it, I wondered if it has to do with thoughts around compilation and whether the language designers think you’re mostly making user-interactive programs or libraries? It makes sense to me that scripting languages like Python, Ruby, and Perl would have print built-in since you always have to have the interpreter along with you, so all the basics should be there. (The original Batteries Included Python promise, for example) But perhaps the Go developers thought you wouldn’t always be printing to the command line so a more efficient binary could be compiled by forcing you to import the functionality? I’m not entirely sure. 

The next thing I started thinking about, again due to learning Rust, was the mutability of variables. In most languages I’ve come across (I think all, except Haskell) all variables are mutable by default. It almost seems pointless to have a non-mutable variable. I understand why many languages have the concept of a “contanst” modifier/keyword. Unlike normal variables, THIS ONE does not change. But the opposite seems so weird since most of what we often do in programming involves changing the value in a variable. Perhaps as I learn more about Rust, I’ll understand their reasoning, but this seems completely backwards to me.

Both Rust and Golang use structs to organize variables where Ruby, Python, and Java use objects. But when both Go and Rust allow you to “attach” methods/functions to structs – is there a true distinction between object-oriented programming and struct-based programming? It seems like it’s just semantics (in the generic sense of the word) – at least at the level at which I program. The only difference I can see is that structs don’t have inheritance, although Go’s “types” solve some of the same problems.

Today’s (the day I’m writing this, not the day it’s going to be posted) shower thought was about programming language versions. On one end you have Java (I think now on version 22) and C# (now at version 12). On the other you have Python and Ruby (both at version 3). Perl essentially stopped at 5 with Perl 6 evolving into Raku. I don’t know what Java is up to. But I think C# is actually using the versions correctly – I’ve heard that each version introduces completely different ways of doing things and that the way you program C# depends strongly on when you jumped in. This is why Python is probably never moving to v4 unless they need to make some kind of huge change. Rust is an outlier with year-based versions. I guess that’s fine, but doesn’t tell you anything like a proper semantic versioning could. 

Finally, I know that Rust is the newest of all the programming languages I’ve learned, but I really love how new projects are started. Python isn’t horrible, but it’s currently suffering from a lots of ideas, none of which has complete market share. You could do a simple virtual environment or you could do a more complex virtual environment/lock file situation with Poetry. (And there are about another half dozen variations on these two themes) But Rust….Rust deserves a chef’s kiss. When you start a new project with “cargo new project-name”, not only does it set up your directory structure, but it does a whole bunch of great setup tasks. It creates your Cargo.toml file (with Python, which only really started supporting toml files at the project level a few years ago, you need to look at documentation to figure out what goes in there) so that you have all the basics in there already. But it doesn’t stop there! It also, in a nod to modern programming, creates a git repository AND a gitignore file. It’s a thing of beauty. I would absolutely love for Python to move in this direction officially (not through a random user choice) for their defaults. Even “go mod init” could benefit from setting up a git repo and a git ignore (since the toml is not how Go works – I think they would probably best set up a README.md since Go’s default packaging is through git repos).

,

11 responses to “A few thoughts on Programming languages”

  1. @EricMesa Very thoughtful post.

    As for #Perl, it hardly “stopped at version 5.” (See @shiar’s summary of changes from Y2K’s 5.6 to last year’s 5.38: https://sheet.shiar.nl/perl.) There simply hasn’t been major breaking changes, unlike, say, #Python.

    The community also lacks consensus on the marketing value of a new major version. Some software releases just merrily keep incrementing that number to draw attention and create FOMO, semantic meaning be damned.

    • @EricMesa @shiar PS: In 2020, the #Perl “pumpking” (i.e., release manager) of four years, Sawyer X, announced plans for #Perl7 at that year’s Perl Conference. It was basically going to be Perl v5.32 with sane defaults.

      But certain nasty members of the community bullied Sawyer out of the role in protest. Out of that smoldering crater came a new explicit convergence model: https://perldoc.perl.org/perlgov

    • You’re right. I was overly simplistic in the way I characterized Perl 5. It definitely has not stood still.

  2. @EricMesa
    On your struct Vs object note, if you look at C++ they're exactly the same except for the default is public for structs and private for objects. So yeah I would say that yourlnare correct in your assessment that objects are just syntactic sugar on top of structs

  3. @EricMesa I think that rust non-mutable defaults have more to do with borrow checking than how common they are to use. The rules for mutable variables are more complex, and they want you to be signing up for that complexity before you take it on.

    • Fair enough. I’m very, very early in my Rust exploration. I just learned about variable shadowing and how the shadow can’t be mut (if I’m remembering correctly).

  4. @EricMesa as far as immutability by default, that ensures that variables can be properly optimized by the compiler (since immutable variables are less overhead, as far as I understand) and it also means developers are less likely to just forget to use "const" (which we do a lot – just try adding eslint's recommended typescript plugin to a project which doesn't have it – you'll see "variable not used – use const instead" everywhere because of the prefer-const rule)

  5. @EricMesa in Go in general except for a very small number of keywords every symbol should be explicitly declared so it’s easy to see where it comes from. And there is a certain bias towards long running servers so printing directly bypassing the logging system is not something you want to do by mistake. 5ere might not be a stdout that is accessible. Even for CLIs often one wants various options for output, json vs can or whatever, so you want something other than printing to stdout.