Random Thoughts on Programming Languages

I noted with interest that Microsoft is delving into Rust for some things in the OS where they have memory related security holes. 

We seem to need a language for each of the following:

  • OS
  • Desktop GUI
  • Web front end
  • Web back end
  • Services (web backend without a front end)
  • Data querying 
  • Systems (data serving, near the metal)
  • CLI utils to listen to the GUI or the anti-GUI user or the scripters
  • Script for the scripters

C and C++ remain relevant for the OS but Rust seems to be scratching at the surface.

Javascript rules the browser (written in C++) but WebAssemby (also written in C++) is scratching at the door and will bring many languages to play there once WA has cut ties with JS interop dependency for DOM and HTTP coms.

The web backend and services is a mess of nearly every language on the planet. From JS to Ruby (wretch). Even here JS dominates with Node. The rest of the field is up for grabs.

Data querying is still SQL followed my a mishmash of things for querying noSQL datastores, usually some form of JSON over REST, though binary serialization in gRPC is growing for both data and services.

Systems are still primarily C and C++ but Java and C# play some Part in some database platforms. Go, Rust and others are also knocking on the door. Kubernetes is a good Go example, a tech that is red hot right now.

The CLI world is a free for all. Python is fast becoming a favorite for the automation and ML scripters. This category does seem to favor interpreted over compiled but even that is a pile of chaos and debate.

One thing is certain. There is only one master language in all of computing. Heaven help us. It's English. And there is no consistent compiler, interpreter or IDE for the foul thing.

OOP in D, Go and Rust

Caveat Emptor: I am no expert in any of these languages. DO NOT read this post and assume any such thing.

Picking up where I left off with Hello World in D, Go and Rust in VS Code, this post restarts the thread of my personal learning and exploration of these three programming languages:

Of these three, only D is really an OOP language, but I wanted to see how close I could get in Go and Rust. I started with D and then morphed and adapted as I moved to Go and finally to Rust. The code in this experiment is overly simplistic and meant only to explore basic OOP principles. Nothing in this code is meant to demonstrate best practices in any of these languages.

Update All

First things first. Like my blog, the system on which I wrote the previously noted post has been neglected these past few months. I updated VS Code from June 2019 v1.26.1 to October 2019 v1.40.2. I had Auto Update enabled, so my extensions were updated as well: DLang to v 1.16.7, Go to 0.11.9, and Rust (rls) to 0.7.0.

Next I updated my language environments by downloading and installing the latest releases for Windows:

*dirty: Yeah, I wondered about that too. Apparently it is an artifact of their build system after moving to GitHub. Nothing to worry about. Probably.

The D installer did ask for some VC runtime redistributables or and install of Visual Studio. I already had Visual Studio 2019 installed but would later remember that it had been uninstalled and I had not installed the VC++ dev options. This left no VC redistributables on my machine apparently, as I would soon learn when trying to use the Rust compiler.

dlangvcmingw

Validate Prior Code

The D and Go compilers worked with the prior post’s Hello World code just fine. The Rust compiler complained like this:

PS D:\langc\rust\Hello> rustc app.rs
error: linker `link.exe` not found
   | = note: The system cannot find the file specified. (os error 2) note: the msvc targets depend on the msvc linker but `link.exe` was not found note: please ensure that VS 2013, VS 2015, VS 2017 or VS 2019 was installed with the Visual C++ option error: aborting due to previous error

This was easily resolved by closing VS Code, opening Visual Studio Installer, and adding Desktop development with C++ in Workloads. Opened VS Code again and ran rustc app.rs and the problem was solved.

The app.exe grew by a few bytes for D and Rust but shrunk just a little for Go. I’m not certain why but I thought that was interesting.

Code in GitHub

Rather than listing out all the code in this post, I put the old Hello World code and the new code for this post into https://github.com/tylerjensen/d-go-rust which should make it easier for you to see the effort as a whole. There is nothing special about this repo. It’s just a learning playground and definitely does not purport to be a demonstration of proper practices in any language, let alone best. So reader beware!

Object Oriented Programming

There is no shortage of opinions available on the web as to what constitutes “Object Oriented Programming” but there are certainly some comment themes. Here are the few principles that I selected to use in my attempt to build and compare some OOP code in D, Go and Rust. This is not a comprehensive list and definitely not an attempt to authoritatively define OOP.

  • Objects / Classes — data structures and methods (or functions)
  • Encapsulation — data and logic protection (private vs. public)
  • Composition — support for “has a” relationships
  • Inheritance — support for “is a” relationships
  • Polymorphism — an object that “is a” thing can be used as a thing
  • Open Recursion — a thing can call itself and access its data (this or self)

There may be many other elements of OOP and some of them may be important to you, but for now, let’s see if we can limit it to the scope defined in the bullets above, at least for this foray into learning three new languages.

General Approach

To keep things simple, I’m limiting each effort to one or just a few files. Implementation of methods/functions are simplistic console outputs. Only one complexity was added because I wanted to see how each language deals with date and time. As simple as date/time may seem to humans, it’s another thing entirely to a computer and each language has its own way of dealing with the variety of RFC standards for date/time data.

Another effort I’ve made to keep this simple is that each example is built as a simple console application. No libraries built. No HTTP listener. No windows. No command line arguments. No real architectural organization or realistic naming or code documentation. This is an effort to learn the basics of the languages rather than their best practices. I’ll leave that to the experts in each language.

I’ve tried to write the same code in each language. Mostly. There are differences, especially with the Rust code. The Rust compiler is rather opinionated and to eliminate warnings, I’ve complied with its suggestions.

Here’s the list items I’ve tried to create in each code base:

  • Interface Printable with Print method
  • Abstract class Person that implements Printable interface
  • Demographics class that has a DOB date and encapsulates age behind a GetAge method
  • An Employee class that inherits from Person and composes a Demographics instance
  • An overridden Print method in the Employee class
  • Overloaded methods that take a Person, Employee and Printable as an argument to examine polymorphism

OOP in D

I chose to start in D because it really is an OOP language where Go and Rust, technically speaking, are not. This would give me a simpler entry point into building some code that looks like the kind of OOP that I’m used to seeing in C#. This would allow me to cover most of the elements of OOP that I wanted to explore.

The D code is split into three files, each defining a “module” because within a given module, all private and public class members are accessible to all others. This means that to ensure encapsulation, you have to use separate modules which are defined by the module keyword and follow the convention that the module name is the same as the file name.

I’m not going to show all the code here, but here’s the “per” module which has the interface, abstract class, and the composable class defined. It’s not all that different from my C-based languages including my favorite C#.

module per;

import std.stdio;
import std.datetime;

public interface Printable 
{
  void Print();
} 

public abstract class Person : Printable
{
  public void Print() 
  { 
    writeln("Person printed.");
  }
  public string Name;
}

public class Demographics
{
  private int age;
  public Date DateOfBirth;

  this(Date dob)
  {
    DateOfBirth = dob;
  }

  public int GetAge()
  {
    SysTime today = Clock.currTime;
    
    // Example of open recursion - 'this'
    this.age = today.year - DateOfBirth.year;
    
    return age;
  }
}

The rest of the code can be found here: https://github.com/tylerjensen/d-go-rust/tree/master/D/oop

It’s rather self explanatory for anyone familiar with C-based languages. I won’t spend much time explaining the code. My lazy approach to looking at overloading and polymorphism can be found in the app.d file in the poly methods.

OOP in Go

The first thing an OOP developer runs into with Go is that it has no concept of a class. Rather data defined in a “struct” and those structs can have functions added to them outside the scope of the struct using what Go calls a “receiver” meaning that the function extends the struct with behavior. Encapsulation is easy. A struct member that begins with a capital letter is public. A lowercase letter is private. But similar to D, unless that struct lives in a separate package, the private member is accessible. Unlike D, a package must be in it’s own directory, so you will find the per.go and emp.go files in their own subdirectories.

Go does have a concept of an interface but it does have have an explicit declaration of an object implementing that interface. There are some advantages to this and if you assign a pointer of an instance of a struct to an interface variable and your struct does not implement receiver functions that comply with the interface, the compiler will spit that back out at you.

Here’s the same code as shared above for D. The per.go file is fairly easy to read. In fact, I quite like Go’s readability.

package per

import (
  "fmt"
  "time"
)

type Printable interface {
  Print()
}

type Person struct {
  Name string
}

func (p Person) Print() {
  fmt.Printf("Person printed.\n")
}

type Demographics struct {
  age         int
  DateOfBirth time.Time
}

func (d Demographics) GetAge() int {
  t := time.Now()
  d.age = t.Year() - d.DateOfBirth.Year()
  return d.age
}

And honestly, I’m not missing those semi-colons.

As you peruse the code https://github.com/tylerjensen/d-go-rust/tree/master/Go/oop, you will see that in app.go that Go does not support overloaded functions (methods), unless they are receiver functions for different types but that’s outside the scope of this post. It does allow you to declare a variable of type interface and then assign it a pointer to a struct variable that implements that interface in receiver functions.

OOP in Rust

Of all three languages, I had more trouble with Rust. It’s paradigms are more foreign to my C# mind, but that’s okay. In most respects, it is very similar to Go but has no garbage collector and relies on a lighter, faster approach called ownership and borrowing. I’m not sure if we call that OB or BO. Either way it is a constraint that does make you think more about resource usage and what you’re doing with your data structures.

Rust does support a concept of an interface but they call it a trait. Encapsulation was easier but I ran into trouble thinking I needed to do something similar to Go’s packages using Rust modules (“mod” keyword). I could not get the trait defined in one module and used in another. I did find some documentation and feature requests that indicate that this is not supported. So I dropped back to a single file and one module.

Here’s a partial listing of app.rs found here https://github.com/tylerjensen/d-go-rust/blob/master/Rust/oop/app.rs 

pub trait Printable {
  fn print(&self);
}

pub struct Person {
  pub name: String
}

impl Printable for Person {
  fn print(&self) {
    println!("Person Print {}", self.name);
  }
}

pub struct Demographics {
  // Cannot make this private and not require initialization 
  age: i32,
  pub date_of_birth: chrono::DateTime<chrono::offset::Utc>
}

impl Demographics {
  pub fn calc_age(self: &mut Self) -> i32 {
    self.age = Utc::now().year() - self.date_of_birth.year();
    return self.age;
  }
}

You can see that Rust does have explicit implementation for a trait (interface) and that you must pass a reference of the struct to a function of an “impl” code block for a given struct. This is definitely different than Go. But if you look carefully, you’ll see that if the implementation is going to change data in the struct, you must pass “self” as a mutable pointer. This means that calling the “calc_age” function can only be done by an instance that is declared at mutable using the “mut” keyword. If you mess up on this, the compiler will let you know.

Conclusion

I don’t know what’s next but I’m having fun. I don’t think I will continue to try to push Go and Rust into the OOP hole. They have strengths that are worth exploring without being constrained by an approach the languages were not designed to support. Exploring and learning their best practices could be fun.

Each language has its strengths and quirks. Go is certainly more popular and Rust is growing. The D language remains rather small in terms of market penetration and is nurtured by a smaller group of very dedicated computer scientists. I do not know if it will survive. Go and Rust definitely will as their communities are much larger.

More fun to come. Stay tuned.

Hello World in D, Go and Rust in VS Code

A few days ago a friend asked me what languages I’m learning. I told him I had been rather lazy of late and was not currently studying any new languages in my programming repertoire. So he said something like this:

每天早上刷牙后研究一种新语言。
Měitiān zǎoshang shuāyá hòu yánjiū yī zhǒng xīn yǔyán.

When I told him I had no idea what he just said, he laughed and explained that he is learning Mandarin and had just told me, “Study a new language after you brush your teeth every morning.” To be honest, I pulled the above Mandarin from Google Translate because I had no way to remember exactly how he had said what he said. But he had successfully goaded me into getting back on the polyglot track. We talked about Rust and Go and D. I’ve played with D some years ago, but have never done anything real with Rust, Go or D.

Here’s Part 1 of my journey through these three languages. The Hello World with a tiny input twist looks like this:

image

I decided to get each of them working in Visual Studio Code. I’m a Windows user, so if you’re on a Mac or using Linux, your mileage will vary. Hopefully what I’ve found here will help you get a start on one or all of these languages as well.

Visual Studio Code

First things first. If you don’t already have it installed, follow the link in the header above and get and install it. It’s simple so I won’t walk you through it here. My first love is the big old fashioned Visual Studio and I’ll continue using it for most of my work, but I wanted to learn more about VS Code as I learn more about these three programming languages. Here’s the version I’m using:

image

Of course you can use your own favorite editor. We’re not going to use any special integrations in VS Code for the Hello World examples here.

Hello in DLang

You can get a pretty good history of DLang here. There are three compilers that support D. In this post, we will only use the DMD compiler, the reference compiler for the language. Download and install DMD. Once installed, open a new console and enter the command DMD. You should get something like this:

[path]>dmd 

DMD32 D Compiler v2.086.0
Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved written by Walter Bright

Once you have the compiler installed, install the DLang VS Code extension for D. (There are several. After some experimentation, I found that I liked this one the best but this is by no means a comparison of them, so I’m not mentioning the ones I decided not to use.)

I created the following Hello World in app.d and ran the DMD app.d command in the terminal window in VS Code.

import std.stdio;

void main()
{
	string name;
	write("Hello, what's your name? ");
	readf("%s\n", &name);
	writeln("Hello, ", name);
}

The app.exe produced was 312KB in file size. At run time, it consumed 1,728KB.

Hello in GoLang

I downloaded and installed Go and then the Go VS Code extension. The extension is built by Microsoft, so I expected the VS Code experience to be superior to the other two languages. I was right. This included the automatic suggestion to install several additional Go related extensions which I did.

I was able to run the following code through the debugger, but rather than get into debugging these languages for this post, I wanted to focus on building an executable that would be as close to the same modified Hello World as I could get.

package main

import "fmt"

func main() {
	var name string
	fmt.Printf("Hello, what's your name? ")
	fmt.Scanf("%s\n", &name)
	fmt.Printf("Hello, %s\n", name)
}

The command line to build the executable was a little more tricky but not bad. There are many sites that can help you here. The command go build -o app.exe app.go produced an app.exe that 2,164KB file size but only consumed 1,424KB at runtime. That surprised me a bit. I expect that Go is packing in a whole lot of things into the executable that my little code base is not using.

Hello in Rust-Lang

Next I downloaded and installed Rust for Windows and then added the Rust(rls) VS Code extension. When I first tried to compile this bit of code, I got an error error[E0601]: `main` function not found in crate `app` which seemed odd since there was definitely a main function. After closing and starting VS Code again, the rustc app.rs command line compiled the executable just fine. Perhaps a path had not been picked up.

use std::io;

fn main() {
	let mut name = String::new();
	println!("Hello, what's your name? ");
	io::stdin().read_line(&mut name).expect("Failed to read line.");
	println!("Hello, {}", name);
}

The Rust compiler wins the size competition with an executable coming in at on 154KB for a file size and only 324KB at runtime. Call me impressed.

Video Tutorials

If you like to learn by watching, here are three fairly good YouTube tutorials that I’ve found. There are many more of course. I’m not saying these are the best, but I liked them. I will return to them a few more times as I continue to learn each of these languages.

What’s Next

Most programming language documentation will take you on a journey of variables, control flow, etc. I figure you can read those on your own. Google works just as well for you as it does for me. So next I want to explore the following. Hold me to it.

  1. How to write object oriented code
  2. How to write SOLID code
  3. How to write a RESTful service client and server
  4. How to write scalable code (threading, message passing, etc.)

That seems like a fair number of things to explore. There are a multitude of others that may emerge as I walk down these three learning paths.

Update

In preparation for more on this language exploration, I have create a GitHub repo here.