Home
Blog
Recent Posts 2
Updated
Dot Net Perls

When to Use Switch in C#

It is said that the decisions we make determine the lives we live. For developers, we must determine whether to use an if-statement or switch. Should developers use switch more often? And if so, when should switch be preferred—should we always replace if-chains with switch blocks?

Let's consider an if-else chain that tests for numbers. If all the cases are constant, we can convert the if-block into a switch statement. In newer versions of C# we can use ranges and expressions in switch statements—so even more if-chains can be converted.

There are some benefits that can be realized by using switch. The switch statement:

Can occasionally be optimized better than an if-else chain, but this probably will only happen in situations with constant integer cases.
May appear more elegant and polished in the code—the code looks like it has been written with more care.
May be slower than an if-statement if one case occurs frequently, and an if-statement check for it first.

If I am handling a set of char values, like lowercase letters or punctuation I would prefer a switch. My thinking is that if there is a complete set of cases we want to consider, and they are all mostly equal in importance, and the cases are simple values like char or int, prefer a switch. Otherwise, reach for the old standby if-statement.

When to Use Arrays in C#

Probably my favorite class in C# is the List. It expands to hold as many items as you want, and it can be set (through the generics syntax) to hold any element type you desire. But arrays in C# offer some clear benefits, too—though they are less often needed.

An array is different from a List mainly because it cannot resize its buffer on its own. An array of 100 elements will always have 100 elements (though elements could be null). For this reason, we should prefer arrays only when we know the exact element count beforehand—like for a buffer of bytes we read data into.

Arrays are preferred only when:

Performance is critical, as arrays may have lower overhead for element accesses in some cases than Lists.
The element count is fixed (as in a buffer we read data into).
Memory usage is an issue—arrays have somewhat lower memory usage than Lists because they cannot resize their buffer, and will never reallocate (which leads to garbage collection).

Basically, if your program's goal is to read strings from a file, you will want a List. But if you want to store 10 strings in a class for later use, a string array is a better choice. Usually the List is the better first choice.

When to Use List Comprehension in Python

Some features of Python are in nearly every guide, but are they are useful in practice? Consider the list comprehension syntax. It does a similar thing to the map built-in in most programs—it creates a new list from an existing iterable.

To be fair, list comprehension has some advantages over the map built-in. It can remove elements with an if-clause at the end. And it returns a list, not an iterable—with map, we would need to further call the list built-in to get a list.

But list comprehension can be worth avoiding because:

It leads to excessively complex syntax.
Other developers may be unfamiliar with the syntax and its quirks.
Other approaches, like for-loops and the map built-in, can accomplish the same sorts of tasks.

In my view, list comprehension is useful for creating lists with straightforward logic—like a list of 100 positive integers. But for complex things, or in cases where a function call is needed, other approaches like for-loops or map are a better choice. It is good to keep list comprehensions, should you decide to use them, fairly short and simple.

When to Use Rc and Arc in Rust

Suppose you (as a Rust developer) have built up a struct instance with some data—like the text of a file. Let's call this struct FileData. And you want to access this data in various functions in the program. Rc or Arc can be used for this purpose.

The program has a couple other structs that are used throughout—let's call them Info and InfoTwo. Many functions in the program have arguments of types Info and InfoTwo. We can put an Rc or Arc containing the FileData on these structs.

Though it is accessible from two structs (Info and InfoTwo) the FileData struct is only resident in memory once. It was never copied—just an Rc or Arc was copied, and this involves just an integer increment, and a small number of bytes. This is called reference counting.

If Info and InfoTwo are passed to different threads, we should place them in Arc—otherwise, we can just use Rc. In my experience, Arc is preferred as most Rust developers want to use threads, and Arc will work correctly on a single thread as well.

This Is My Favorite Java Feature

Though it is similar to languages like C#, Java has some unique features that help improve programs. One feature, the Optional class, indicates whether a value exists or not—it is a way to clarify logic in modern Java programs. I think it is a great feature.

Here's why—without Optional, we might use magic constants on a value like an Int to indicate that no value exists. But with Optional, we can just use Optional.empty and our logic is clearer. Optional in Java is similar to Option in Rust, and an equivalent feature in Swift.

When considering Optional, we should remember that:

It has a learning curve—we need to learn to call isPresent, isEmpty, and use other methods with lambda expressions.
It can cause exceptions in methods like get if used incorrectly.
It may impact performance in a negative way—it should not be used in some lower-level, performance critical code.

By storing an Optional int in a class, we indicate that the value may or may not exist. So every time we access the field, we must use methods on the Optional to get its inner value. Still, Optional is useful in clarifying when a field is valid—and it is one of my favorite Java features.

Visual Studio Code and C#

C# is a Microsoft product at its core, even though it is developed in an open-source way these days. It makes sense, then, that another Microsoft product, Visual Studio Code, has exceptional support for C#. I installed the C# language support in VS Code and tested it out.

With features like IntelliSense (this is the auto-completion logic where the editor guesses what you are going to type when you press period after a type name), VS Code offers many advantages over Notepad. I am not sure if they still call it IntelliSense, but it is helpful for serious developers.

Other features of VS Code with the official C# extension include:

Support for renaming types and variables (this is simple refactoring).
More advanced refactoring support, when you right-click on a something and go to Refactor.
Errors that appear directly in the code where they were triggered.
Syntax highlighting to make programs easier to read.

Overall I found the C# support in VS Code to be superior to that in other editors. One big drawback of VS Code is its reliance on Chromium to render its user interface, which makes it slower than programs like Zed. But other than the slight slowdown, it is both more compatible with languages and systems, and has more features, making Visual Studio Code a good choice for developers new and experienced alike.

Gemma3 4B Local LLM Review

About three months ago, Google released its open-weights Gemma 3 LLMs. These models can be downloaded and run on computers with enough RAM using the Ollama program. This is fine—but are the models worth bothering with?

To test, I downloaded the 4B models, as my Mac mini M1 with 8 GB of RAM cannot run anything larger than that. The gemma3 4B QAT (quantization-aware training) model has 4.3 billion parameters and can run on the unified 8 GB memory of the Mac mini M1. Not only this, but Ollama supports GPU-acceleration of the model, so it is fairly fast in responding.

I tested the default gemma3 4B quantized model, and the QAT model, and my findings are that:

Gemma3 4B QAT is indeed better at providing answers than the non-QAT model, so I would always recommend the QAT models (look for "qat" in the model name).
The 4B models show considerable perplexity—it is best to only ask the model questions that correspond to popular Google searches, as this is mostly what it seems trained to answer.
Gemma3 4B QAT generates about 15 tokens per second on the M1 chip and 8 GB of RAM.
On the Mac M1 with 8 GB RAM, the Gemma3 4B-IT-QAT model causes macOS to use about a gigabyte of swap memory, even when doing light web browsing.

Definitely prefer QAT—there are cases where the QAT models got the answer right, and the default model did not. Gemma3 has an enjoyable style, and it uses emoticons in its greetings. It is a friendly, and even useful, assistant—it is possible to use it with only 8 GB of RAM on a Mac, but 16 GB would allow faster operation of the computer without swapping.

GNU Image Manipulation Program

Sometimes it is necessary to give a program a beautiful and elegant name. In other cases it doesn't matter. For instance, the open-source image editor uses the name GNU Image Manipulation Program (GIMP). At least it is possible to figure out what the program is used for from its name.

Several years ago, I had a project that I used GIMP for on macOS, and it was difficult for me to figure out how to use it. It was frustrating. I came close to giving up, but I persisted, and I was able to finish the images required.

In 2025, a new version of GIMP has been released, and it seems to have some big improvements. It has a more intuitive interface that will be easier for newcomers to figure out. For the most part I have been pleased with GIMP 3, although I haven't done any complicated image editing yet. It does have some rough edges still, but for those who are not going to make monthly payments for a more powerful program, it is a great deal and highly recommended—GIMP 3 is a step forward.

When to Use Records in C#

Often when developing C# programs we have small classes that only have a couple fields or properties. For example, a Point may have just two fields—its coordinates. Do these types need an entire class, with a constructor? Or should we condense the logic and keep the program smaller?

With records, we can specify—in a single line—a class that has some fields. Each field has a type and a name. There are some limitations with records, however, so it is best to use them only when certain conditions are true. We can use records when a class:

Has no methods, properties, or custom constructors.
Has no complex inheritance issues (a derived class) and does not implement any interfaces.
Is unlikely to need any of the previously-mentioned features in the future.

Records, which are also available in Java, can define a class with different fields in a single line. They remind me of tuple classes in Rust as well. If I were developing a program in C# or Java, I would aspire to use records when adding types—this would help keep the code base smaller and easier to manage.

Should Interfaces Be Preferred in C#

There are some things about C# that are confusing, even for developers who have known the language for a while. For example, there are many ways to have a type share parts of itself with another type. We have inheritance, abstract classes, and interfaces.

When should we use a normal class, and then derive another class from it? And when should an abstract class be used? Interfaces meanwhile are not a class at all, but allow us to treat different classes as though they are the same, through the interface.

After working with languages that do not support inheritance at all, I suggest just using interfaces:

Interfaces allow us to unify 2 different types and share code that acts on those types through the interface.
Interfaces avoid complicated issues with base constructors.
Interfaces are used throughout the built-in types in .NET, so developers can figure out how to use them without much trouble.

I am not against using language features to improve program quality, but inheritance often seems to result in excess complexity—to understand one class, you need to understand all the base classes. Instead, with interfaces, our code is flatter and more local to the class. Class derivation can be useful, but in my view, interfaces usually are a better choice.

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