Friday, July 17, 2026

Crack 1.7 Released

After a long period of release inactivity, we are pleased to report the release of Crack 1.7.  

 This release has been a long time coming, largely for personal reasons.  I've been working from home ever since the pandemic, which eliminated two hours of commuting per day during which I would do open source development.

 However, I'm happy to say that I retired from Google in June and can now work on whatever I want, so my first order of business was to get this release out the door.

 There are a number of important bug fixes in this release, mostly dealing with a few internal details that broke things under some very specific conditions.  However, there are a couple of notable features:

 Anonymous Classes

You can now create anonymous classes to handle one-off data packaging situations.  For example:

     a := (class * {
        int a;
        oper init(int a) : a = a {}
        int oper call(int b) {
            return a + b;
        }
    })(100);
 
    # "result" is set to 150.
    result := a(50);
 
As the example suggests, these are mainly useful for the implementation of closures.

Closures

The "closure" annotation uses anonymous classes to create one-off functors bound to the values of local variables:

    import crack.functor Functor1;  # Needed for a @closure macro with 1 param.
 
    @import crack.ann impl;  # Needed for the @closure macro.
    @import crack.closures closure;
 
    void enclosingFunction(int a, int b) {
        func := @closure[a, b] (int c) : int { return a + b + c };
        // func is now a Functor1 that can be called as func(value)
    }

Various Enhancements

As noted earlier, there's a regex2  module that makes use of pcre2.  crack.http.comm2srv provides HTTP serving functionality through the crack.comm2 framework.  There's now also a crack.utf8 module for dealing with UTF8 strings.

Is this the end?

 This may very well be the last version of  Crack that I release.  While I still believe in the language, and still use it regularly for lots of things, it's pretty likely that I'm the only one who does :-)  There are probably better things I can focus on than improving Crack, at this point.

I do have a lot of ideas for another language that borrows a lot of concepts from Crack -- not really a "Crack 2.0" so much, though.  It certainly won't be compatible.  I'll post here if and when there's something to show for it.  

Thursday, June 18, 2026

New Significant Fixes

The Crack main repository hasn't been very active for a while.  This has been primarily due to my involvement in other projects, a number of which make use of the language.  But the 1.7 release, specifically, has been blocked by one particular bug literally for several years -- I simply haven't had enough consecutive productive hours to focus on it.

But I'm happy to say that in the past two days I have fixed both that bug and another.  Both had extremely simple fixes, literally one or two lines of code.  Finding the problem, of course, is another matter.  The Crack executor is as magnificent a beast as has ever emerged from the twisted, steaming cauldron of my mind, and I'm sure it's been several years since I last engaged this beast beyond a superficial level.  So I feel rather proud that I'm still able to ferret out it's deepest imperfections when presented with a reproducible error case.

Both bugs were related to class instances -- constant, static, global structures that constitute Crack's RTTI mechanism.  

The older one ("older" as in "known longer") was a naming collision in Generic class instance global variables.  It results in a massive dump of the LLVM IR code for the program along with an assertion failure indicating an "uninitialized global" (without naming the global, of course).  This was caused by passing the current parser context to the function that generates the class instance for a new generic, which is meant to accept the context of the new generic class (more specific typing would have prevented this). 

I encountered the newer bug while trying to debug the older one.   It turns out that when you forward declare an appendage, the "appendage" flag of the reused TypeDef object created during processing of the forward declaration wasn't getting updated.

With these issues crushed, and a number of new features in the standard library, I now feel inspired to get to a 1.7 release.  There are still quite a few test failures that have crept in over the years to debug, but I don't expect they're anything major.  Time to move to the next milestone!