D Programming Language: A Hidden Gem

D is an interesting language. For some reason, I have an emotional connection with this language and I believe that it is the subject of the biggest unfairness story in the history of software development. To me, it is the best programming language in the market for the reasons I am going to state below. However, this language is underestimated, underrated, and despised in the programming circles because it doesn’t have a strong backer. In this article I want to talk about, and give some credit to D, an underrated sibling of C++, Java and C#. The D programming language (or sometimes referred as Dlang) is designed as a higher-level alternative to C++. Initially developed by Walter Bright in 2001. His purpose was to improve C++ by refining syntax and he brought some features from other languages like Java and Python. Over the years, D has evolved. It is a practical and efficient language for real-world applications. This is a simple Hello World app in D: The D programming language is great for different kinds of software projects. It’s really good for programs that need to talk directly to computer hardware, like operating systems or device drivers. This is because D lets programmers manage memory and access hardware directly. It also has tools that make writing command-line programs easier, helping to quickly create programs that can handle files, text, and user inputs. Furthermore, D is also suitable for making websites and server applications. It can deal with lots of users at the same time and can help make web servers that are fast and reliable. D makes it easier to keep web projects organized and can handle complex tasks well. Even though it’s not the most common choice for web development yet, D has everything needed to build both the front and back end of web applications efficiently. It’s a good option for programmers who want their projects to run fast and smoothly. Here’s an example of a simple function in D that takes two integers as parameters and returns their sum: Another important aspect of D is its syntax, which is clean and expressive, especially you are familiar with C-style languages. The language eliminates many of the historical complexities found in C++. Features like contract programming, true modules, and unit testing are built into the language. It shows D’s commitment to modern programming paradigms. These integrated tools and techniques do not only make the language more powerful, but also encourage good programming practices. This example shows how to define a simple class in D, demonstrating object-oriented programming capabilities: As you can see, not too different from C++, C# and Java. One of the foundational features of D is its system-level capabilities like C and C++. It provides low-level memory access and manual memory management facilities. This makes D suitable for applications where direct hardware access and control over memory allocation are needed. On the other hand, D also introduces garbage collection, which is not a standard feature in traditional system languages like C++. In D, pointers can be used for direct memory access, similar to C and C++. See example below: In D, organizing code is easier and definitely better than in C++. Instead of using separate header and source files, D uses modules like Java does. Just as a reminder, a module is like a box that holds related pieces of code together under one name. This helps prevent mix-ups when different parts of the code have the same names. So, with D, your code is more tidy, easier to handle, and works more efficiently. See the documentation here for the details of modules in D. One of the mind blowing capabilities of D is built in unit tests. I love it. As far as I know, this is unique to D, no other languages have it. We always talk about Test Driven Development but never talk about the overhead it creates. In D, unit tests can be written alongside the code, and they can be compiled and run automatically. The integration of unit testing into the language simplifies the testing process, making it a natural part of the development workflow rather than a separate task. See the following example: Contract Programming, also known as Design by Contract (DbC), allows developers to specify conditions for a function, such as preconditions, postconditions, and invariants. These contracts act as formal, executable specifications of the function’s behaviour. For example, a precondition might specify that a function’s argument must be non-negative, a postcondition could assert that the function returns a positive value, and an invariant might maintain that the internal state of an object remains consistent after the function is executed. By integrating these contracts directly into the language, D enables developers to write more reliable and self-documenting code, making it easier to identify logical errors and enforce correct usage. Here’s a simple example: In this example, we define a BankAccount class with a method withdraw that demonstrates the use of Design by Contract principles. The preconditions check that the withdrawal amount is positive and does not exceed the current balance. The postconditions ensure that the balance remains non-negative after the withdrawal and that the withdrawal operation correctly reduces the balance. The invariants, though not explicitly defined in a separate block here, are inherently enforced by the preconditions and postconditions to maintain a consistent and valid state of the account balance. As you have seen above, D is well ahead of its time and all of the popular mainstream programming languages. It definitely deserves a way better place and popularity in the market but somehow it couldn’t reveal its potential. This is why I wanted to dedicate this blog post to introduce D for people who hasn’t heard yet. Further resources: Suleyman Cabir Ataman, PhD

Go Language: A Modern Take on System Programming

Today, I want to talk about a new generation language which gains ground among developers. Go also popularly known as Golang, an open-source programming language created at Google by Robert Griesemer, Rob Pike, and Ken Thompson in 2007. It was specifically designed to improve programming productivity in the era of multicore processors, networked systems, and massive computation clusters. Go’s syntax is quite simple. It has a blood from C as C++, Java, C# etc. but they removed semi-columns as opposed to the traditional C type languages. A simple program to print “Hello, World!” in Go looks like: Since its beginning, Go has found favour in developing web servers, data pipelines, and even in cloud-native applications. Its straightforward concurrency model and rich standard library make it particularly attractive for backend developments. Moreover, its strong support for integration has led to wide use in infrastructure tools and projects; Docker and Kubernetes being two prominent examples. Strengths and Weaknesses of Go Go’s primary strength lies in its balance of simplicity, efficiency, and performance. It achieves what many older languages struggle with — making concurrent programming intuitive and safe through lightweight “goroutines” and channels. This concurrency model enables developers to build scalable and performant applications that can handle numerous tasks simultaneously without the complexity of traditional thread management. Another major strength is its compilation speed. Go compiles directly to machine code, which not only speeds up the execution but also simplifies cross-compilation. This is particularly advantageous for developers working on large codebases that need to be maintained across different platforms. Go’s standard library is also praised for its comprehensiveness, offering packages for a wide array of applications — from HTTP server development to cryptography to data manipulation. This reduces the need to rely on third-party libraries, which can help avoid dependency management issues. Furthermore, Go’s tooling is a highlight. With built-in tools for testing, formatting, and documentation, it provides a productive development environment that encourages better coding practices and reduces the effort needed for code maintenance. Despite its strengths, Go is not without its drawbacks. The lack of generics has been a longstanding point of discussion within the community. This means that developers often want to use interfaces and type assertions, which can lead to less type-safe code and can affect performance due to runtime type checking. Go’s simplicity also comes with trade-offs. The language’s deliberate omission of features like exception handling, assertions, and annotations can make error handling verbose and less intuitive. Its stance against functional programming constructs and the lack of features like constructors or destructors may also be seen as a limitation by developers accustomed to other object-oriented languages. Another criticism is that while Go’s garbage collector has improved significantly, garbage collection can still introduce latency, which is a concern in real-time system applications where performance is critical. Key Areas of Usage Go is often chosen for backend development due to its efficient handling of concurrent processes, making it well-suited for cloud services, APIs, and microservices. It’s also prevalent in the development of distributed systems and DevOps tools due to its performance and ease of deployment. Infrastructure projects, particularly those in the containerization and cloud orchestration space, such as Docker and Kubernetes, have been built using Go and are a testament to its capabilities in handling large-scale distributed systems. Additionally, Go is commonly used for command-line tools and network servers, where its static compilation and performance characteristics make it an excellent choice. Companies looking to build scalable and maintainable server-side applications often turn to Go. Programming Languages Challenged by Go Go challenges several established languages across different domains. For system-level programming, it poses a modern alternative to C and C++, providing memory safety and garbage collection, which can reduce the risk of security vulnerabilities inherent to manual memory management. Against dynamically-typed scripting languages like Python or JavaScript (Node.js), Go competes with its type safety, which can result in fewer runtime errors and better performance in large and complex systems. It also provides a more straightforward concurrency model compared to Node.js, which relies on the event-driven model and callback functions that can lead to callback hell. In the arena of enterprise application development, Go stands as a competitor to Java and C#. While it doesn’t offer the same level of ecosystem maturity, its simplicity and the productivity gains it offers through its tooling and straightforward language features make it a compelling option for enterprises looking to streamline their backend systems. Go in Action Some of the most well-known projects built in Go include: Numerous companies have embraced Go for various aspects of their operations. A tech giant like Google obviously, but also: In conclusion, Go distinguishes itself with a compelling mix of performance, simplicity, and a strong toolset, making it a favourite among developers for high-performance and scalable applications. While it may not be the perfect fit for every project, its adoption by major industry players showcases its significant impact and growing relevance in the software development landscape. Suleyman Cabir Ataman, PhD

Rust: A Modern Time Challenger to C++

For developers of my generation, C++ was the go-to language. It was everywhere, especially when you needed to write code that is fast, efficient and object oriented. C++ gave us the control we need to use every bit of performance and also extendable language to adapt modern programming techniques. We didn’t really think that one day there would be another language that could ever challenge C++ in what it did best. To me, C++ is still the king of all programming languages. However, Rust is not a rival to undermine. In this blog post we will see some details about Rust and compare it to C++. Let’s dive into it. Rust’s story begins in 2010 by Graydon Hoare, who was working at Mozilla Research at the time. Mozilla saw a potential in Rust and backed the project. The primary aim was to solve the problems that developers face with C++. What made Rust special was its emphasis on memory safety and concurrency, areas where C++ has shown vulnerabilities due to its age and design philosophy. Rust presents a significant challenge to C++ because it was designed (at least aimed) to provide memory safety and prevent segmentation faults without sacrificing performance. It’s accomplished by its ‘ownership’ model, which ensures memory safety without needing a garbage collector. Unlike C++, Rust enforces rules at compile-time which often leaves much of the responsibility for memory management and safety to the developer, increasing the potential for errors. The structure of Rust is both familiar and unfamiliar. Its syntax comes from C, which means that it looks like C++ in some ways. It provides a sense of familiarity, but it also contains elements from some modern functional languages, making it effective and powerful. Rust’s powerful type system and borrow checker (which we will go into details in the following lines) ensures the memory safety and thread safety, encouraging a more disciplined approach to coding. As a tradition let’s see a simple “Hello, World!” in Rust: The Strengths and Weaknesses of Rust When discussing the merits of Rust, one can’t help but be impressed by its commitment to memory safety, which is at the core of its design. Rust achieves this through a unique system of ownership with a set of rules that the compiler checks at compile time. No garbage collector is needed, and no memory is accessed unexpectedly, greatly reducing the risk of memory leaks and security vulnerabilities. The language’s rich type system and emphasis on safe concurrency practices are major assets. Rust allows you to confidently run code in a multi-threaded environment without the fear of data races. It’s not just the memory safety that’s attractive, but the ease with which Rust handles concurrent programming that makes it appealing in an era where multicore processors are the norm. Another strength is the modern tooling, Cargo is used for managing packages and dependencies. This has been a breath of fresh air for developers who are used to wrestling with complex build systems. The compiler is incredibly helpful, with descriptive error messages that often tell you not just what went wrong, but also why and how you might fix it. On the documentation front, Rust is really good. They can be found on https://www.rust-lang.org/learn. The language’s guides and standard library documentation are comprehensive and serving as a valuable resource for both novice and experienced programmers. However, Rust is not without its challenges. The language’s learning curve cannot be omitted; even though it’s powerful ownership and borrowing concepts, it can be difficult for newcomers to grasp. This complexity can sometimes make Rust seem intimidating and less approachable than other languages. Rust’s compile times have been a point of discussion as well. They can be slow, particularly for larger or complex projects, which can be a little bit frustrating for developers who are accustomed to the quicker compile times of some other languages. While Rust’s ecosystem is growing, it is still weak compared to any main-stream language. The availability of third-party libraries is not as extensive as in some other languages, which can sometimes result in the need to write more code from scratch. Additionally, because the language enforces strict coding practices, developers may find themselves battling the compiler to get their code to work as intended, leading to a harder learning process and a potential frustration. In summary, Rust brings a lot to the table with its emphasis on safety, concurrency, and modern tooling. Its growing ecosystem and improving compile times are signs of a vibrant and evolving language. However, its complexity and learning curve are factors that new Rust-lovers will need to navigate carefully. Rust vs C++ When compared to C# and Java, Rust is a system-level language that gives you manual control over memory management. It doesn’t have a garbage collector running in the background, which is a core aspect of both C# and Java since they are designed for application-level software. Rust’s compile-time memory and concurrency safety guarantees are not found in these languages. However our main focus will be the battle between C++ and Rust. When we talk about Rust in relation to C++, it’s important to compare them across several key criteria that are typically important for developers and the tasks they aim to accomplish. Performance: Rust was designed to offer performance equal to C++. Both languages give the developer strong control over system resources and memory. However, Rust’s guarantees of safety do not come at a cost to performance, which is often a concern with high-level languages. This is a significant achievement, as traditional languages that offer higher levels of safety and abstraction tend to suffer from a performance. Rust achieves this by combining sophisticated compile-time checks with efficient runtime characteristics and also ensuring that resource-intensive tasks are handled with efficiency. Memory Safety: C++ allows for powerful, low-level memory manipulation, but this comes with the risk of memory safety issues. Rust’s memory safety features are designed to catch and prevent errors at compile time, reducing the risk of crashes and security vulnerabilities in the final program. Rust introduces a unique concept known as the “borrow checker.” Every piece of data has a single ‘owner’ at any given time. The borrow checker enforces this by ensuring when the ownership of a value is transferred (known as ‘moving’), the original variable can no longer access the value. This prevents accidental modification or deletion of values that are in use elsewhere. Another key feature is Rust’s approach to memory allocation and deallocation. In C++, developers must manually manage memory, allocating and freeing it, which can lead to errors. Rust automates this process through its ownership system, where each piece of data has a clear owner, and memory is automatically freed when the owner goes out of scope. Concurrency: Concurrency in C++ is prone to race conditions and requires careful management of threads and locks. A race condition is a type of concurrency bug that occurs when two or more threads or processes access shared data concurrently, and at least one of them modifies it. Rust’s approach to memory safety naturally extends to its handling of concurrency. The language’s ownership and type system make concurrent programming more approachable by preventing data races at compile time. Learning Curve: C++ has a complex syntax with many features that can be difficult for beginners to grasp. Rust also has a steep learning curve but for different reasons. Its concepts of ownership and lifetimes are unique and can be challenging to understand for those used to the freedom of C++’s memory management. Talent Pool: Due to its long history, there is a larger pool of experienced C++ developers compared to Rust. This makes it easier for companies to find skilled developers and community support, resources, learning materials etc. Modern Features: Rust benefits from being a newer language with features designed for today’s programming needs, such as a powerful macro system and zero-cost abstractions. C++ is constantly being updated and has been catching up with modern features like lambda expressions and auto keyword. However, Rust was built with these modern paradigms in mind from the start. Tooling and Compiler Feedback: Rust’s compiler (rustc) and its package manager Cargo, provide a seamless development experience. The compiler is particularly known for giving helpful error messages, a feature that many C++ compilers are famous for not having. Ecosystem and Library Support: C++ has been around for decades, resulting in a vast ecosystem and comprehensive standard library. Rust is younger with a smaller ecosystem, but it’s rapidly growing and has a central repository for sharing packages, crates.io, which is analogous to C++’s various library repositories but with integrated tooling. Established Standards and Best Practices: C++ has well-established coding standards and best practices developed over decades. This extensive body of knowledge helps guide developers in creating efficient, reliable, and maintainable code. Even the famous Gang of Four Design Patterns started as a C++ practice first. Templates: C++’s template capabilities are more advanced and allow for a higher degree of code reuse and compile-time polymorphism. This can lead to more flexible and efficient code, albeit at the cost of increased complexity. Community and Industry Adoption: C++ has been widely adopted in the industry for years, making it a default choice for many systems-level applications. Rust’s adoption is growing, especially among companies that prioritize safety and performance, and it’s endorsed by industry giants like Microsoft and Google for certain applications. C++ and Its Deep Ties with C: C++ has a key aspect which makes it one of the strongest languages of all times which is the intrinsic relationship with the C. Any valid C code can typically be compiled with a C++ compiler and C++ is fully capable of using C libraries directly. This compatibility allows developers to leverage a huge volume of existing C libraries in C++ projects. Nearly all major operating systems, including Unix/Linux, Windows, and macOS were written in C. This widespread use emphasizes the importance of being able to interface with C, as it forms the base of many low-level system components. However, Rust can interact with C through FFI (Foreign Function Interface) which allows Rust to call C functions and libraries. This process is not as straightforward as in C++. The developer must explicitly define the interface and ensure that the data types used are compatible with C standards. The process obviously requires more effort, particularly in ensuring that the safety and correctness which Rust is famous for. In short, C and all its ecosystem is huge, rich, essential for a system programming language, and C++ holds a way stronger position with its deep relationship with C. Rust in Action As a modern language, Rust is being used for network services, embedded systems, and even command-line tools. Popular frameworks in Rust include Actix for web development and Serde for serialization and deserialisation. Getting started with Rust is straightforward with the Rust toolchain installer, rustup. As for IDEs, there are several options like Visual Studio Code, IntelliJ Rust, and others that offer great support for Rust development. Several high-profile projects have been built with Rust, testifying to its growing popularity. These include Servo, a parallel browser engine project initiated by Mozilla, and Amazon’s Firecracker, which is used to manage microVMs in AWS Lambda and AWS Fargate. In conclusion, Rust is an important aspect and good player in programming, specifically system-programming domain. It will hold a stronger position in the future as well. However, even though we cannot know what will happen next with a perfect precision, I believe that C++ still maintains and will maintain its position as the king of all programming languages, and will not be easily overthrown by Rust, not last but least its relationship with C. Suleyman Cabir Ataman, PhD