logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·01.11.26
← Back to news

A Few Good Ideas in Programming Languages

Original article
prydt.xyz|28 points|2 comments|by airhangerf15|Sep 12, 2026

A Few Good Ideas in Programming Languages

Posted: 2026-05-10
Author: Pranoy Dutta
Source: prydt's site

Below is a curated list of programming language features that I find particularly impressive.


1. Flow Typing

One of the most elegant concepts I encountered in the Crystal language is simple flow typing.

Crystal is a compiled language that utilizes static type-checking, yet it adopts a syntax heavily inspired by Ruby. What makes Crystal unique is that it maintains the "feel" of a dynamically typed language by allowing a single variable to be associated with different types throughout its lifecycle—a rarity in most statically typed environments.

How it Works

Consider the following logic flow:

my_var = 5 # The type is currently Int32
assert(my_var.is_a?(Int32))

if some_complex_condition()
  my_var = "hello!" # The type shifts to String
  assert(my_var.is_a?(String))
end

# At this point, what is the type?
# It is now a union: Int32 | String
assert(my_var.is_a?(Int32 | String))

The compiler tracks the variable's type across different regions of the code. As shown in the diagram below:

If you attempt to call a String method on my_var at the end of this block, the compiler will throw an error because the variable is an Int32 | String. To fix this, you must use a type check (like if my_var.is_a?(String)), which narrows the type back down to just a String. This allows for a dynamic developer experience without the typical runtime performance penalties.


2. Borrow Checking

Rust is a systems-level language designed to ensure memory safety without relying on a garbage collector. It specifically targets the "loathsome" data race, which occurs when multiple threads access the same memory location simultaneously, and at least one access is a write, without proper synchronization.

The Borrow Checker is Rust's static mechanism for preventing these races at compile-time. It enforces a strict set of ownership rules:

  • Lifetime Constraint: No borrow can outlast the scope of the original owner.
  • Reference Exclusivity: You must choose one of the following:
    • Exactly one mutable reference (mut T\text{mut } Tmut T)
    • One or more immutable references (TTT)

Comparison to Synchronization

This logic mirrors a readers-writer lock. The fundamental goal of concurrent synchronization is to serialize writes to memory.

Reference TypeQuantity AllowedAccess Level
Immutable (T\text{T}T)≥1\ge 1≥1Read-Only
Mutable (mut T\text{mut T}mut T)111Read/Write

While the borrow checker introduces added complexity, I view it as an elegant, zero-cost abstraction. The complexity is simply a reflection of the inherent difficulties of concurrent programming.


3. Contract Programming

Most developers are familiar with the assert statement for checking invariants (e.g., "this tree must remain balanced"). However, the D programming language (which is significantly underrated) takes this further with Contract Programming, providing formal syntax for function- and object-level invariants.

assert vs. enforce

D distinguishes between internal logic errors and external failures:

  • assert: Used for correctness bugs. If this triggers, the programmer made a mistake.
  • enforce: Used for external issues (e.g., invalid user input or environment failures) and throws an exception.

Function Contracts

D supports in (pre-conditions) and out (post-conditions). For example:

int daysInFebruary ( int year ) 
out ( result ) { 
    assert (( result == 28 ) || ( result == 29 )); 
} do { 
    return isLeapYear ( year ) ? 29 : 28 ; 
}

In this case, the out block ensures that any return value other than 28 or 29 is flagged as a logical error.

Class-Level Invariants

D also allows invariant() blocks to ensure object data remains consistent across all operations.

Example: Bank Account Implementation Banking Icon

class BankAccount {
    private double balance;

    invariant () { 
        balance >= 0; // Object-level invariant: balance can never be negative
    }

    this ( double initialBalance ) 
    in ( initialBalance >= 0 ) { // Pre-condition
        balance = initialBalance;
    }

    void deposit ( double amount ) 
    in ( amount > 0 ) 
    out ( balance == old.balance + amount ) { 
        balance += amount;
    }

    void withdraw ( double amount ) 
    in ( amount > 0 && amount <= balance ) 
    out ( balance >= 0 ) { 
        balance -= amount;
    }

    double getBalance () 
    out ( result >= 0 ) { 
        return balance;
    }
}

Using an invariant() block is far more maintainable than manually calling a consistency check at the start and end of every single method; it provides a clear, idiomatic way to guarantee object integrity.