Home
Blog
Recent Posts 2
Updated
Dot Net Perls

Advantages of Enums in Rust

I do not know everything about every computer language, or even every one I write about on this site. Instead, I learn as I go along. From other languages like C# I was familiar with the concept of enums—types that store known values and can be referenced by name.

But in Rust, enums have an additional feature—they are an algebraic data type. This means a value in an enum can reference some data—like a struct instance, a String, a tuple or a number.

In practice, this means we can use a single enum to refer to multiple data types:

An enum with two variants, each with a different data type, can be tested in a match statement and we can evaluate the data at runtime.
We do not need to know which kind of attached data an enum instance will have until runtime.

So we can create a Color enum, and it could have a value of Red with a String, or a value of Blue with a usize instead. And we can refer the Color as meaning either Red or Blue—and a String or usize only in appropriate cases. This can simplify some programs where we must return many types of data from a single function.

The Problem With Windows Forms and WPF

There are many articles about Windows Forms and WPF on this site—and they have been helpful to people for a long time. With Windows Forms and WPF developers can make Windows applications that have windows, buttons, dialog boxes, and C# or VB.NET code.

But as competing technologies like web browsers have become more powerful and widespread, Windows Forms and WPF have become less useful. It is possible to build a simple web server in nearly any language that serves HTML pages and handles input from clicks and POST requests. And web browsers have many advantages over WinForms and WPF:

They are available on all platforms, even mobile phones.
Due to the popularity of the Internet, web browsers will be supported and maintained for a long time.
With time more native features like WASM and better UI controls will become available.

For some applications that need native speed, like text editors, web browsers and even games, it is necessary to use native UI controls. But for the vast majority of applications that one might need, web browsers are probably a better platform to target. Of course, for older applications that have already been written, continuing to support Windows Forms and WPF is necessary.

Rust Borrow Checker Tips

Suppose you are writing a Rust program, and you are having problems with the borrow checker. The compiler is giving you messages about "use of moved value" and "cannot borrow data as mutable." Should you give up?

No, you should not give up. Instead, here are some tips for dealing with the borrow checker.

Store all elements in a struct, and then reference those elements by index from elsewhere in the program.
Use indexes (like usize values) instead of references.
Clone structs when needed to fix some "moved value" issues, and wrap structs in Arcs to make cloning much faster.

Basically in Rust it helps to know what struct owns all the memory in a program. Then you don't have to worry about the memory anymore—you can just access the data by index, referencing the owner struct. In this approach, most structs do not need to store references to other structs.

When to Use a Hash Table

When we write code in a language like C#, Java, Python or Rust we often have to choose between arrays or lists and hash tables. An array or list stores elements one after another. A hash or dictionary stores elements in locations that are based on the values of the elements themselves (hash codes).

Often we can realize a performance improvement in programs by using hashed collections correctly. If our program loops over an array to find an element by value, it is likely faster to use a hash table instead.

Here are some signs it is worth trying a dictionary:

We often need to test if an element is contained in a collection of elements—has the element already been added?
We often need to insert or remove elements (not just at the end).
Nested loops can lead to significant slowdowns—could an inner loop be replaced with a hash table lookup?
We want to represent sparse data, such as an array where only a small number of elements have existing values.

If a program needs the packed elements in a linear collection, arrays or lists are a better choice. They are more memory-efficient and faster to loop over. But if the program has excessive searching by value, a hash collection is probably an improvement.

The Problem With 2D Arrays

2D arrays are a common topic that people want to know about. How can you make a 2D array in C#, Python, Java, Go—what is the syntax, how can you access elements? But for the most part the articles I have on 2D arrays ignores the main problems with 2D arrays.

Basically the best time to use a 2D array is never. It is usually better to just use one-dimensional arrays, nested arrays (which are like jagged arrays), or even hashtables. Often, data are sparse, and 2D arrays in most languages use memory for all elements—this wastes a lot of memory.

Here are some things I have found:

2D arrays end up having syntax that is complicated and hard to read.
Other data structures like nested arrays or hashtables are more memory-efficient (and faster).
For numerical processing, using third-party libraries is almost always a better solution than trying to do things directly with 2D arrays.

2D arrays, like recursive methods, are a feature that most programs would be better off not using. Other solutions are simpler and usually faster. I suppose, for completeness, learning about 2D arrays is worthwhile however.

Fastest Programming Language

Some years ago I had a C# program that was taking too long to finish. The time required for it to finish processing was approaching a minute. For an interactive program, this was not acceptable, so I focused on optimizing the program.

Eventually I added multi-threading to the program, and it finished in less than 100 milliseconds. However, I was still curious as to whether other languages, like Go or Rust, could be faster than C#.

I ported the program to Go, and although I changed the algorithms a bit to be more efficient (this often happens when porting) the program was at least 20% faster, even without any optimization-specific work. The Go program took 80 milliseconds to finish.

Finally, I ported the Go program to Rust, and surprisingly this version was not only plagued with fewer bugs (it worked correctly right away), but it also was twice as fast as the Go version, at 40 milliseconds.

In the comparison of C#, Go and Rust, I found that C# and Go were similar, although Go was faster for command-line programs as it was compiled ahead-of-time. Rust meanwhile was the fastest programming language to use, and this was before any optimization work was done—it was just the first compiling version.

This Is My Favorite VB.NET Feature

Even though it is used for many programs, VB.NET is mostly ignored even by its creators. Other languages like C# get much more attention; new features are often exclusive to C# in .NET updates.

But VB.NET persists, and I have found it has some good points—even features that C# does not have. One thing it does, for example is support case-insensitive syntax. So we can use "sub" in place of "Sub" for a subroutine.

This is helpful for VB.NET for these reasons:

Some keywords, like "ByRef" and ByVal can be difficult to remember how to capitalize.
Keywords like Dim and As are short and may be left lowercase for readability.
The language is supposed to use capital letters, but it is easier to type lowercase letters.

It is a good compromise to just leave the syntax case-insensitive. This can also speed up development if you have a capitalization inconsistency but the program still compiles correctly. Case-insensitive syntax is a useful feature for VB.NET.

Time-Saving C# Feature

In the past I spent a significant amount of time working on large C# projects with many files. The C# language can be verbose and require excess time to create new classes—particularly several years ago.

One newer feature in C# that I feel can make developing large, multi-file programs easier is the "global using" directive. While "using" as a directive only applies to the current file, "global using" applies globally to all files in the project.

So each file that you create—like a new class file—you can omit the commonly-needed using directives. In many projects, a single directive is used in many places—like the System namespace for programs that write to the console, or System.Text for programs that use StringBuilder. I feel global using directives are a valuable time-saving (and file-size-saving) feature in this language.

Most Useful Go Article

For the most part, Go is a language where things are done in an obvious way. Slices, for example, are done on units of the original type, like elements in an array. But taking substrings is somewhat more complicated.

In Go, strings can be thought of as collections of bytes, and collections of characters (or runes). This is because some Unicode characters (like those with accents) have more than one byte. But ASCII strings have just one byte per character.

The Go substring article is one of my most useful:

It shows how to convert a string to a rune slice, and then when we want a substrings, we just use a slice of that.
It shows that ASCII strings can have substrings taken directly (with no rune conversion step).
It explains what to do when there is no Substring function—take slices instead.

Substrings in Go are done a little differently than in other languages like C#, but the idea of using slices for substrings makes sense. Writing the Go substring article helped me figure out this important aspect of Go.

Favorite Feature in Ruby Language

Ruby is a language similar to Python but with object-oriented design, and an emphasis on syntax that makes programs easier to read and write. It is an enjoyable language to use, although I have not written any large or serious programs with it.

Ruby has traditional loops like for and while, but I find the iterator syntax, and methods like times, upto, downto, step and each to be more elegant. The iterators can even reduce bugs by avoiding the need for indexing variables.

Iterators have many diverse benefits:

They read more like English, so we can say "zero upto ten" for a loop from zero to ten.
As noted, they can reduce bugs by giving us elements in an array, like with each, not an iteration variable into the array.
We can handle range checks in one place in the loop, and not worry about them elsewhere.

Although the iteration block syntax is difficult at first, it makes sense the longer you use it. And many simple iterators do not require block syntax at all—we can just use the do-keyword instead. Having used Ruby in some projects, I find iterators to be one of Ruby's best features.

More
Dot Net Perls is a collection of pages with code examples, which are updated to stay current. Programming is an art, and it can be learned from examples.
Donate to this site to help offset the costs of running the server. Sites like this will cease to exist if there is no financial support for them.
Sam Allen is passionate about computer languages, and he maintains 100% of the material available on this website. He hopes it makes the world a nicer place.
An RSS feed is available for this blog.
Home
Changes
© 2007-2025 Sam Allen