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.

Windows Service in the D Programming Language

Nine months ago I blogged about my curiosity about the D programming language. It is possible that this curiosity is turning into a hobby. Time will tell. Recently I decided to create a Windows Service written in the D programming language. I’ll share my journey to that end here.

When I started I assumed it would be easy to find examples in the open source world from which I could learn. That assumption turned out to be mostly false. I found some posts on the forum that were helpful. I then dug up an email address using that famously free detective, Google. Graham Fawcett was very helpful in sharing some code with me but for some reason I could not get it to work.

After a week or more of evenings attempting to find a solution, I gave up and offered a bounty on the forum. And Vladimir Panteleev, a regular D community contributor, came to my rescue and gladly took the $100 bounty to be applied toward other issues he would like to see resolved. My deep thanks to both of these community members.

As it turns out, the code that Graham shared with me would have worked except the Win32 bindings code had an x64 bug that would not have manifested itself had I been compiling for x86. Specifically, the winsvc.d code file contained the line:

alias DWORD SERVICE_STATUS_HANDLE;

I took Vladimir’s advice and changed it to:

alias size_t SERVICE_STATUS_HANDLE;

And then later pulled in his final fix as;

mixin DECLARE_HANDLE!("SERVICE_STATUS_HANDLE");

I won’t try to explain the differences here. In any case, the handle in x64 world needed to be a ulong and it was getting declared as a uint (C# equivalents here). And once that was resolved, I was very happy to see the code work.

You can get or read the code for that first success on GitHub. I refactored that code using a reference app in C++ that followed a familiar pattern having written many Windows Service in C#, even to the point of writing a short cut to standing up a Windows Service in .NET.

In any case, if you are curious to see my first real foray into the world of D programming, you can check out the code on GitHub. It even includes a minor improvement suggested by a forum member already. And if you have questions or need help, please leave a comment and I will do my best to help.

DMD x64 with Visual D in Visual Studio 2013 on Windows 8.1

About ten days ago, I installed the latest Visual D from GitHub and ran into some problems when trying out the DMD/GDC console application to use the “DMD | x64” config to compile a simple console app as an x64 native Windows application.

While I have not yet tested it, I believe the installer would have worked out of the box on my Windows 7 machine. But on my Windows 8.1 laptop, I had some trouble. Rather than boring you with all the things I tried, I will just share what finally worked for me.

Here’s the console app code I was working with:

import std.stdio;

int main(string[] argv)
{
    writeln("Hello D-World!");
	readln();
    return 0;
}

I had downloaded and installed Visual D with VisualD-v0.3.37.exe. I had also downloaded and installed the latest DMD compiler from dlang.org. In the process of figuring things out, I also reinstalled Visual D.

In Visual Studio, I created a new DMD/GDC console app from the D Language tab in the new project dialog. This console app template comes preconfigured with a configuration called "Debug DMD|x64" and I switched to that. But when I hit F6 to build, I would get the following error:

------ Build started: Project: ConsoleApp1, Configuration: Debug DMD x64 ------
Building Debug DMD x64\ConsoleApp1.exe...
LINK : fatal error LNK1181: cannot open input file 'user32.lib'
Building Debug DMD x64\ConsoleApp1.exe failed!
------

After doing some browsing and searching, I found the known issues page and the fix described on the page did not work but it did lead me to do some more digging and experimenting until I found that modifying the sc.ini file with some very specific changes solved the problem. Here are the relevant lines, as modified, in my sc.ini file that finally made it possible for my little program to compile. (update—only the Environment64 changes are required—while Rainer Scheutze suggests that the paths can be modifed in Visual Studio, I’ve not been able to make that work).

[Environment64]
   ; original LIB="%@P%\..\lib64"
   LIB="%@P%\..\lib64";\dm\lib;"C:\Program Files (x86)\Windows Kits\8.0\Lib\win8\um\x64";%DMD_LIB%

This post will be my saved notes for the next time I have to configure a Windows 8.1 machine for D programming language in Visual Studio 2013 (and beyond). And I hope you find it useful too.

Diversions in the D Programming Language

I am not a systems programmer, meaning I do not write operating system device drivers or file systems or operating system modules, etc, all written in a language that will compile down to raw machine code. I write in C# primarily which is arguably an applications programming language, running in the much loved .NET Common Language Runtime.

The vast majority of systems programming is done in C and C++. And for some reason, C++ has always been a daunting mess of libraries, odd syntax and pointer and memory allocation madness to me. Even setting up an environment to get the right build libraries, the right compiler and linker, etc., have always led me to fits of impatience. And for that reason and many others, I have stuck to C# and applications development.

But every once in a while, I look in on systems programming to see if anyone has really solved the problems I love to hate with respect to C and C++. And for a few years I’ve read a little about the D programming language here and there. A week ago, over the weekend, I decided to give it a try and really see what I could learn.

I have to say, I have been impressed. The D programming language offers a few things that I would dearly love to see in C#.

1. Exception Safety – the scope keyword

void abc() 
{ 
  auto resource = getresource();  // acquire some resource 
  scope(exit) resource.close();   // close the resource 
  doSomeProcessing();             // do processing
}

As C# programmers, we’re used to the try..catch..finally blocks. And we clean up a resource in the finally block. The trouble with that is many lines of code can end up separating your resource acquisition code from your resource cleanup code. Yes, with vigilance and well written tests, this is okay. But wouldn’t it be cool to be able to tell the compiler, “Hey, when I’m done with this thing I just now created, clean it up for me, no matter what code comes after this in this method.” I would love to see the scope keyword added to C#.

2. Concurrency approach

int perThread;
shared int PerProcess;

In C#, when you declare a class level variable, it is automatically shared between threads. You can use the [ThreadStatic] attribute to get a per thread instance of a given value or object. But it then has to be static. With the D programming language, you get thread safety in class variables. To override that safety, you have to explicitly tell the compiler you want the value shared. While I’m not advocating a change to C# in this regard, I would love to have a way to assure that a variable cannot be modified across thread boundaries.

3. Message based threads

import std.concurrency, std.stdio;
void main() {
   auto low = 0, high = 100;
   auto tid = spawn(&writer);
   foreach (i; low .. high) {
      writeln("Main thread: ", i);
      tid.send(thisTid, i);
      enforce(receiveOnly!Tid() == tid);
   }
}

void writer() {
   for (;;) {
      auto msg = receiveOnly!(Tid, int)();
      writeln("Secondary thread: ", msg[1]);
      msg[0].send(thisTid);
   }
}

For me, this is perhaps the coolest part of the D programming language’s base class library which they call Phobos. Note that main spawns a thread calling writer. The loop in main then sends a message to writer and the loop in writer receives the messages and operates on them and then sends a message back to the original thread.

You can learn a lot about D on www.dlang.org and read more about D concurrency on Informit. And if you want to play with D in Visual Studio, hop on over to see VisualD on dsource.org.