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:
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.
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.
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:
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.
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:
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.
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:
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.
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.
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:
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.
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:
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.
Usually C# is a pleasant language to work with—it makes logical sense and can accommodate fairly complex programs. But some features in the language are inconvenient or downright flawed. One feature I like to avoid is the Clone method.
Part of the ICloneable interface, the idea behind Clone is that we have this interface that we use to define how an object is cloned (duplicated). But the interface does not do that. It does not specify to what extent the object is cloned. Here are the problems:
So ICloneable is supposed to give us a standard way to duplicate objects, but it just makes us more confused when we cannot figure out what the method does with regards to nested objects. It is a counterproductive interface—one that makes programs harder to use and more confusing. For the most part, it is best to avoid ICloneable and Clone altogether.
Suppose a person ends up on Dot Net Perls, and this person is reading about how to use the List in C#. This is a great thing to do. But over time my List article, along with most of the other ones, has accumulated lots of links to other articles on this site.
From a certain perspective, this is good—someone might want to browse around and view related topics. But for someone who is focused on the List, it is probably better to get rid of distractions and only show the links if requested.
To this end, I have added a Links button that, when clicked, shows all the links on the page in a separate place at the top. I hope this helps makes the pages less confusing, and also makes it possible to browse the links and go to a different page if desired. Try it out—it works the same way as the zooming images feature.