A Few Good Ideas in Programming Languages
Recorded: Sept. 12, 2026, 5:09 p.m.
| Original | Summarized |
prydt's site prydt's site home A Few Good Ideas in Programming Languages Posted: 2026-05-10 Author: Pranoy Dutta Here are just a few programming language features I love: # my_var's type here is Int32 if some_complex_condition() # my_var's type here is String # What is my_var's type here? What's most interesting about this is that there is some time when my_var is just a Int32, there is a region where it is guaranteed to be a String and then there is a region where the compiler cannot actually guarantee one or the other... so its type is the union of all the possibilities. Now if you try to run a String method on my_var, it'll fail because its not a String, its a Int32 | String and the compiler will force you to add a check like if my_var.is_a?(String) which narrows the possible types to just a String. Any borrow must not out-live the scope of the owner exactly 1 mutable reference (&mut T) This might remind you of a readers-writer lock which is a lock which allows many readers OR a singular writer. This is because to prevent data races, we only need to synchronize reads with respect to writes. The point of concurrent synchronization is to serialize the writes to a given memory location. But D also has enforce which is used to mark a difference in semantics. Asserts are used for program invariant violations. If an assert is triggered, this should indicate a correctness bug in our program. enforce instead throws an exception due to some external issue: something like a user input out of bounds or environment issue. Additionally, D has syntactic support for pre- and post-conditions for functions. Here's an example taken from Programming in D: } do { Here the daysInFebruary function has a post-condition which is that it should only ever return 28 or 29; everything else is definitely a logical error in the function. invariant() { this(double initialBalance) void deposit(double amount) void withdraw(double amount) double getBalance() This invariant() block is far cleaner and easier to maintain than having some consistency check function run at the beginning and end of every class method, and it has idomatic meaning. |
Pranoy Dutta explores several valuable concepts in programming languages, focusing on features that enhance safety, expressiveness, and maintainability. One significant concept is flow typing, exemplified in languages like Crystal and TypeScript. Flow typing allows a language to maintain a dynamic feel while retaining static type-checking. This is achieved by allowing a variable to potentially hold multiple types throughout its lifetime, resulting in the variable's type being the union of all possibilities, such as an integer or a string. This system enables compile-time mechanisms to perform type narrowing by requiring explicit checks, forcing the programmer to confirm the specific type before performing type-sensitive operations, which helps in making compiled languages feel dynamic without incurring significant runtime penalties. Another discussed feature is borrow checking, central to the memory safety guarantees of Rust, a systems programming language that avoids garbage collection. The borrow checker statically prevents data races, a common source of bugs in concurrent programs arising from simultaneous, unsynchronized access to shared memory. It enforces strict rules regarding borrowing memory, ensuring that any reference cannot outlive its owner's scope and restricting access to exactly one mutable reference or one or more immutable references. This mechanism acts as an elegant, zero-cost abstraction for concurrency control, conceptually similar to a readers-writer lock, where synchronization is applied to serialize writes to memory locations to prevent data races. The third area of focus is contract programming, which involves defining and enforcing program invariants. While simple assert statements are used to report violations of program invariants, the author distinguishes between asserts, which indicate correctness bugs within the program, and enforce statements, which signal errors caused by external issues, such as invalid user input or environmental constraints, often throwing exceptions. Furthermore, D supports specifying pre- and post-conditions for functions, allowing developers to precisely define the expected state before and after a function execution. Class-level invariants offer a cleaner method for guaranteeing object data consistency. For instance, defining an invariant in a class can ensure that object data always remains consistent, leading to more manageable and idiomatic consistency checks compared to embedding consistency validation within every method. |