tag:blogger.com,1999:blog-87561682857635839412024-03-14T00:36:41.605-07:00Crack Language Newsmindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.comBlogger44125tag:blogger.com,1999:blog-8756168285763583941.post-57024005584013375072020-01-17T13:56:00.000-08:002020-01-17T13:56:57.755-08:00Crack 1.6 ReleasedWe are pleased to report the release of crack 1.6. This version focuses on a few features that I have wanted to add to the language for a long time:<br />
<br />
<h4>
The "is not" operator ("!is")</h4>
This fixes a long-standing wart. Up until 1.5, the only way to check if an object is "not identical" to another object was to negate the result of "is". Since this is a very common thing to do when verifying that an object is not null, the codebase was scattered with code like "if (!(x is null))" which is as painful to read as it is to type.<br />
<br />
1.6 adds the "!is" operator (which is simply syntactic sugar for "!(a is b)").<br />
<br />
<h4>
Safe Navigation </h4>
<div>
It's not uncommon to have a sequence of field dereferences where you want to check every step along the way for null and return a null (of the type of the final dereference) if one of those dereferences fails the check. Many modern languages support doing this in a very lightweight form using the "safe navigation" operator. Crack is now among them. So we can now say:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">x := foo?.bar()?.baz; # x is null if foo, foo.bar() or</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> # foo.bar().baz is null</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<h4>
<span style="font-family: inherit;">Attribute Accessors</span></h4>
<div>
<span style="font-family: inherit;">It is useful to be able to use the same syntax for field access whether a field is being accessed directly or via a method (i.e. a "getter" or "setter"). Crack 1.6 now provides this by allowing you to define accessor methods:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">class Person {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> # We would normally just define "String name" as our field</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> # unless we needed to do something special but this </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> # illustrates the usage of the feature.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> String __name;</span></div>
<div>
<span style="font-family: "Courier New", Courier, monospace;"> String </span><span style="font-family: "Courier New", Courier, monospace;">oper .name() { return __name }</span></div>
<div>
<span style="font-family: "Courier New", Courier, monospace;"> String oper .name=(String val) { return __name = val }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">cout `$(person.name)\n`;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">person.name = 'Frodo';</span></div>
<div>
<br /></div>
<div>
<span style="font-family: inherit;">There's also the usual round of bug fixes and smaller features.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
So check it out at <a href="http://crack-lang.org/">http://crack-lang.org</a></div>
<div>
<br /></div>
<div>
Happy hacking!</div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-72882708840573564592019-07-02T11:19:00.002-07:002019-07-02T11:19:40.884-07:00Crack 1.5 Released!After a very long time (during which I've mostly been working on <a href="http://github.com/google/mawfs">MAWFS</a>) I'm finally getting around to releasing a new version of Crack. This is mostly just bug fixes on 1.4, but there are a few new big features:<br />
<br />
<ul>
<li>Lambdas. You can now create a function as an expression, for example: <span style="font-family: Courier New, Courier, monospace;">lambda int(int a, int b) { return a + b }</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">Auto imports. You can now put all of your commonly used imports in an auto-import file and have them be imported on demand by any modules that need them.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">Experimental new command line processing.</span></li>
</ul>
<span style="font-family: Arial, Helvetica, sans-serif;">Look for a new docker image in another day or two.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Enjoy!</span>mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-58892903036327641912018-07-27T11:36:00.002-07:002018-07-27T11:38:48.459-07:00Crack 1.4 Released!I am pleased to announce the release of Crack 1.4. The latest release includes:<br />
<br />
<ul>
<li>The RawPtr class (for breaking reference cycles)</li>
<li>Function elision (let's you remove a function from a derived context at compile-time)</li>
<li>Fixed event handling in termui.</li>
<li>Fixed memory management in EventManager</li>
<li>Minor enhancements to NML HTML generation.</li>
<li>Fixed assertion failure when dereferencing an undefined forward class.</li>
</ul>
<div>
<br /></div>
<a href="http://www.crack-lang.org/download.html">Download from here.</a><br /><ul>
</ul>
Happy cracking!<br />
<br />mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com2tag:blogger.com,1999:blog-8756168285763583941.post-76750182226985764202018-03-22T11:49:00.000-07:002018-03-22T11:49:03.830-07:00Crack 1.3 Released!I'm happy to announce the release of Crack 1.3.<div>
<br /></div>
<div>
1.3 mainly includes lots of fixes to keep things working on the latest versions of Debian Linux. However, it also includes a few enhancements to crack.io and crack.net.comm2.</div>
<div>
<br /></div>
<div>
Enjoy!</div>
<div>
<br /></div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-53893541553097468942017-12-15T08:39:00.003-08:002017-12-15T08:39:14.747-08:00Crack 1.2 Released!I am pleased to announce the release of Crack 1.2.
In addition to a number of bug fixes, 1.2 adds a number of new features that have been accumulating for the past few months, including:<br />
<br />
<br />
<ul>
<li>The @cvars annotation (which autogenerates constructors to initialize a subset of instance variables)</li>
<li>The Functor.Wrap classes, which simplify the import requirements for wrapping functions as functors.</li>
<li>Support for relative imports.</li>
<li>Enhancements for protobufs, crypto (AES-SIV and CMAC support), the comm2 communications module and annotations.</li>
</ul>
Enjoy!mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-42226300291918967472017-05-04T12:09:00.001-07:002017-05-04T12:35:50.239-07:00Crack 1.1 Released<html>
<head>
<style>
pre {
border: solid;
border-width: 1;
padding: 10px;
border-color: #fff;
color: #fff;
background-color: #010;
}
span.comment {
color: #0f0;
}
span.keyword {
color: #fff;
}
span.ident {
color: #0ff;
}
span.symbol {
color: #ff0;
}
span.number {
color: #0ff;
}
span.string {
color: #f0f;
}
span.istring {
color: #f0f;
}
a:link {
color: #0ff;
}
a:visited {
color: #0dd;
}
</style>
</head>
<body>
<P>I am pleased to announce the release of Crack 1.1. <P>This release includes:
<UL><LI> <A
HREF="http://crack-lang.blogspot.com/2017/04/tokens-and-xmacros.html">Token
literals and @xmacros</A>. <LI> <A
HREF="http://crack-lang.blogspot.com/2017/04/appendages.html">Appendages</A> <LI> The <TT>crack.net.comm</TT> module, which provides some higher level
functionality for communication systems. <LI> The <TT>crack.eventmgr</TT> module, which allows scheduling events in a
poller loop. <LI> Various minor enhancements and fixes.
</UL> </body>
</html>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com9tag:blogger.com,1999:blog-8756168285763583941.post-39797367179818146832017-04-25T05:06:00.000-07:002017-04-25T05:06:06.107-07:00@tokens and XMacros<html>
<head>
<style>
pre {
border: solid;
border-width: 1;
padding: 10px;
border-color: #fff;
color: #fff;
background-color: #010;
}
span.comment {
color: #0f0;
}
span.keyword {
color: #fff;
}
span.ident {
color: #0ff;
}
span.symbol {
color: #ff0;
}
span.number {
color: #0ff;
}
span.string {
color: #f0f;
}
span.istring {
color: #f0f;
}
</style>
</head>
<body>
<P>Crack annotations are a way to extend the compiler at the parser level. A lot
of them do code generation, for example the <TT>@struct</TT> annotation
generates a class with a constructor: <PRE>
<span class="symbol">@</span><span class="keyword">import</span> <span class="ident">crack</span><span class="symbol">.</span><span class="ident">ann</span> <span class="ident">struct</span><span class="symbol">;</span>
<span class="symbol">@</span><span class="ident">struct</span> <span class="ident">Foo</span> <span class="symbol">{</span>
<span class="ident">String</span> <span class="ident">name</span><span class="symbol">;</span>
<span class="ident">int</span> <span class="ident">val</span><span class="symbol">;</span>
<span class="symbol">}</span>
<span class="comment"># Equivalent to:</span>
<span class="keyword">class</span> <span class="ident">Foo</span> <span class="symbol">{</span>
<span class="ident">String</span> <span class="ident">name</span><span class="symbol">;</span>
<span class="ident">int</span> <span class="ident">val</span><span class="symbol">;</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">(</span><span class="ident">String</span> <span class="ident">name</span><span class="symbol">,</span> <span class="ident">int</span> <span class="ident">val</span><span class="symbol">)</span> <span class="symbol">:</span> <span class="ident">name</span> <span class="symbol">=</span> <span class="ident">name</span><span class="symbol">,</span> <span class="ident">val</span> <span class="symbol">=</span> <span class="ident">val</span> <span class="symbol">{}</span>
<span class="symbol">}</span>
</PRE> <P>Annotations are just crack functions that are executed at compile time. The
only restriction is that they must reside in a different module from the code
that uses them. An annotation is just a public function that accepts a
<TT>CrackContext</TT> object: <PRE>
<span class="keyword">import</span> <span class="ident">crack</span><span class="symbol">.</span><span class="ident">compiler</span> <span class="ident">CrackContext</span><span class="symbol">;</span>
<span class="ident">void</span> <span class="ident">struct</span><span class="symbol">(</span><span class="ident">CrackContext</span> <span class="ident">ctx</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="symbol">...</span>
<span class="symbol">}</span>
</PRE> <P>The <TT>CrackContext</TT> object is an interface to the compiler and
tokenizer which references the context in which the annotation was invoked. For
example, we can consume tokens from the point where the annotation is specified
and generate errors at that point: <PRE>
<span class="ident">tok</span> <span class="symbol">:=</span> <span class="ident">ctx</span><span class="symbol">.</span><span class="ident">getToken</span><span class="symbol">();</span>
<span class="keyword">if</span> <span class="symbol">(!</span><span class="ident">tok</span><span class="symbol">.</span><span class="ident">isIdent</span><span class="symbol">())</span>
<span class="ident">ctx</span><span class="symbol">.</span><span class="ident">error</span><span class="symbol">(</span><span class="ident">tok</span><span class="symbol">,</span> <span class="string">'Identifier expected!'</span><span class="symbol">.</span><span class="ident">buffer</span><span class="symbol">);</span>
</PRE> <P>Code generation in annotations has always been done by injecting tokens and
strings into the tokenizer. We make use of the fact that the tokenizer has an
unlimited putback queue and just "put back" the tokens that we want the parser
to get next in reverse order. There is also an "<TT>inject()</TT>" method on the
crack context that lets you inject a string to be tokenized. <P>Neither approach has been entirely satisfactory. Obviously, generating code
by injecting one token at a time is far too verbose and tedious to use for
anything of any size. And while <TT>inject()</TT> fixes that part of the
problem, it relies on writing code in a string, so:
<UL><LI> <P>The line numbers of the code have to be provided to the <TT>inject()</TT>
function, a technique which doesn't compose well. <LI> <P>Editors don't recognize it as crack code, breaking syntax higlighting and
auto-indent.
</UL><P>A better solution relies on the recently introduced <TT>@tokens</TT> and
<TT>@xmac</TT> annotations. <TT>@tokens</TT> is effectively a "token sequence
literal." It consumes the delimited tokens following it and produces an
expression that evaluates to a <TT>NodeList</TT> object containing those tokens.
<P>This lets us generate crack code defined in crack code. For example, the
following ennoation emits code to print "hello world": <PRE>
<span class="keyword">import</span> <span class="ident">crack</span><span class="symbol">.</span><span class="ident">ann</span> <span class="ident">deserializeNodeList</span><span class="symbol">;</span>
<span class="symbol">@</span><span class="keyword">import</span> <span class="ident">crack</span><span class="symbol">.</span><span class="ident">ann</span> <span class="ident">tokens</span><span class="symbol">;</span>
<span class="ident">void</span> <span class="ident">hello</span><span class="symbol">(</span><span class="ident">CrackContext</span> <span class="ident">ctx</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="symbol">@</span><span class="ident">tokens</span> <span class="symbol">{</span> <span class="ident">cout</span> <span class="istring">`hello world!\n`</span><span class="symbol">;</span> <span class="symbol">}.</span><span class="ident">expand</span><span class="symbol">(</span><span class="ident">ctx</span><span class="symbol">);</span>
<span class="symbol">}</span>
</PRE> <P>In the example above, we use <TT>@tokens</TT> with curly braces as
delimiters. We could have also used square brackets or parenthesis. Delimiters
may be nested, but the symbols that are not being used need not be paired. So we
can also use <TT>@tokens</TT> for asymetric constructs: <PRE>
<span class="ident">void</span> <span class="ident">begin_block</span><span class="symbol">(</span><span class="ident">CrackContext</span> <span class="ident">ctx</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="comment"># The unbalanced '{' is allowed here.</span>
<span class="symbol">@</span><span class="ident">tokens</span> <span class="symbol">[</span> <span class="keyword">if</span> <span class="symbol">(</span><span class="ident">true</span><span class="symbol">)</span> <span class="symbol">{</span> <span class="symbol">].</span><span class="ident">expand</span><span class="symbol">(</span><span class="ident">ctx</span><span class="symbol">);</span>
<span class="symbol">}</span>
</PRE> <P>While useful, <TT>@token</TT> still doesn't let us do the kind of composition
we need in order to be able to generate code. There's nothing like macro
parameters for <TT>@tokens</TT>, they are essentially constants. For
interpolation, we have <TT>@xmac</TT>. <P> <TT>@xmac</TT> is like <TT>@tokens</TT> only with parameters allowing you to
expand other <TT>NodeLists</TT>. For example, here's an annotation to emit
exception classes: <PRE>
<span class="keyword">import</span> <span class="ident">crack</span><span class="symbol">.</span><span class="ident">ann</span> <span class="ident">deserializeXMac</span><span class="symbol">;</span>
<span class="symbol">@</span><span class="keyword">import</span> <span class="ident">crack</span><span class="symbol">.</span><span class="ident">ann</span> <span class="ident">xmac</span><span class="symbol">;</span>
<span class="ident">void</span> <span class="ident">exception</span><span class="symbol">(</span><span class="ident">CrackContext</span> <span class="ident">ctx</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="ident">tok</span> <span class="symbol">:=</span> <span class="ident">ctx</span><span class="symbol">.</span><span class="ident">getToken</span><span class="symbol">();</span>
<span class="keyword">if</span> <span class="symbol">(!</span><span class="ident">tok</span><span class="symbol">.</span><span class="ident">isIdent</span><span class="symbol">())</span> <span class="ident">ctx</span><span class="symbol">.</span><span class="ident">error</span><span class="symbol">(</span><span class="ident">tok</span><span class="symbol">,</span> <span class="string">'Identifier expected!'</span><span class="symbol">);</span>
<span class="symbol">@</span><span class="ident">xmac</span> <span class="symbol">{</span>
<span class="keyword">class</span> <span class="symbol">$</span><span class="ident">className</span> <span class="symbol">:</span> <span class="ident">Exception</span> <span class="symbol">{</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">()</span> <span class="symbol">{}</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">(</span><span class="ident">String</span> <span class="ident">message</span><span class="symbol">)</span> <span class="symbol">:</span> <span class="ident">Exception</span><span class="symbol">(</span><span class="ident">message</span><span class="symbol">)</span> <span class="symbol">{}</span>
<span class="symbol">}</span>
<span class="symbol">}.</span><span class="ident">set</span><span class="symbol">(</span><span class="string">'className'</span><span class="symbol">,</span> <span class="ident">tok</span><span class="symbol">).</span><span class="ident">expand</span><span class="symbol">(</span><span class="ident">ctx</span><span class="symbol">);</span>
</PRE> <P>We have to explicitly set each of the parameters with the <TT>set()</TT>
method. We'll get an error if any of them are undefined when we expand.
Alternately, we can use <TT>@xmac*</TT> to do this automatically with variables
of the same name: <PRE>
<span class="ident">void</span> <span class="ident">exception</span><span class="symbol">(</span><span class="ident">CrackContext</span> <span class="ident">ctx</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="ident">className</span> <span class="symbol">:=</span> <span class="ident">ctx</span><span class="symbol">.</span><span class="ident">getToken</span><span class="symbol">();</span>
<span class="keyword">if</span> <span class="symbol">(!</span><span class="ident">className</span><span class="symbol">.</span><span class="ident">isIdent</span><span class="symbol">())</span>
<span class="ident">ctx</span><span class="symbol">.</span><span class="ident">error</span><span class="symbol">(</span><span class="ident">tok</span><span class="symbol">,</span> <span class="string">'Identifier expected!'</span><span class="symbol">);</span>
<span class="symbol">@</span><span class="ident">xmac</span><span class="symbol">*</span> <span class="symbol">{</span>
<span class="keyword">class</span> <span class="symbol">$</span><span class="ident">className</span> <span class="symbol">:</span> <span class="ident">Exception</span> <span class="symbol">{</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">()</span> <span class="symbol">{}</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">(</span><span class="ident">String</span> <span class="ident">message</span><span class="symbol">)</span> <span class="symbol">:</span> <span class="ident">Exception</span><span class="symbol">(</span><span class="ident">message</span><span class="symbol">)</span> <span class="symbol">{}</span>
<span class="symbol">}</span>
<span class="symbol">}.</span><span class="ident">expand</span><span class="symbol">(</span><span class="ident">ctx</span><span class="symbol">);</span>
<span class="symbol">}</span>
</PRE> <P>Since it just generates a <TT>NodeList</TT>, we can use <TT>@tokens</TT> to
directly generate values to interpolate into an <TT>@xmac</TT>: <PRE>
<span class="ident">method</span> <span class="symbol">:=</span> <span class="symbol">@</span><span class="ident">tokens</span> <span class="symbol">{</span>
<span class="ident">void</span> <span class="ident">foo</span><span class="symbol">()</span> <span class="symbol">{</span> <span class="symbol">}</span>
<span class="symbol">};</span>
<span class="symbol">@</span><span class="ident">xmac</span><span class="symbol">*</span> <span class="symbol">(</span>
<span class="keyword">class</span> <span class="ident">A</span> <span class="symbol">{</span>
<span class="symbol">$</span><span class="ident">method</span>
<span class="symbol">}</span>
<span class="symbol">}.</span><span class="ident">expand</span><span class="symbol">(</span><span class="ident">ctx</span><span class="symbol">);</span>
</PRE> <P>We can also expand an <TT>@xmac</TT> into a <TT>NodeList</TT> using the
<TT>expand()</TT> method with no arguments: <PRE>
<span class="ident">accessors</span> <span class="symbol">:=</span> <span class="symbol">@</span><span class="ident">xmac</span><span class="symbol">*</span> <span class="symbol">{</span>
<span class="ident">void</span> <span class="symbol">$</span><span class="ident">name</span><span class="symbol">()</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">__state</span><span class="symbol">.$</span><span class="ident">name</span><span class="symbol">;</span>
<span class="symbol">}</span>
<span class="ident">void</span> <span class="symbol">$</span><span class="ident">name</span><span class="symbol">(</span><span class="ident">int</span> <span class="ident">val</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="ident">__state</span><span class="symbol">.$</span><span class="ident">name</span> <span class="symbol">=</span> <span class="ident">val</span><span class="symbol">;</span>
<span class="symbol">}</span>
<span class="symbol">}.</span><span class="ident">expand</span><span class="symbol">();</span>
<span class="symbol">@</span><span class="ident">xmac</span><span class="symbol">*</span> <span class="symbol">{</span>
<span class="keyword">class</span> <span class="ident">A</span> <span class="symbol">{</span>
<span class="symbol">$</span><span class="ident">accessors</span>
<span class="symbol">}</span>
<span class="symbol">}.</span><span class="ident">expand</span><span class="symbol">(</span><span class="ident">ctx</span><span class="symbol">);</span>
</PRE> <P> <TT>@tokens</TT> and <TT>@xmac</TT> are both useful tools for doing code
generation in Crack annotations. They will be released in Crack 1.1. </body>
</html>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-58160873086407308252017-04-13T11:10:00.001-07:002017-04-13T14:23:05.653-07:00Appendages<html>
<head>
<style>
pre {
border: solid;
border-width: 1;
padding: 10px;
border-color: #fff;
color: #fff;
background-color: #010;
}
span.comment {
color: #0f0;
}
span.keyword {
color: #fff;
}
span.ident {
color: #0ff;
}
span.symbol {
color: #ff0;
}
span.number {
color: #0ff;
}
span.string {
color: #f0f;
}
span.istring {
color: #f0f;
}
</style>
</head>
<body>
<P>I've recently pushed the code to implement Appendages, which will likely be
the primary feature of the 1.1 release. <P>Formally, appendages are a way to extend the functionality of a class
orthogonal to its normal inheritance hierarchy, and specifically to its instance
state. In other words, they are classes consisting only of methods that can be
applied to any object derived from a specified base class, called the "anchor"
class. <P>Taking the example from the manual, let's say we have pair of classes for
representing two dimensional coordinates: <PRE>
<span class="keyword">class</span> <span class="ident">Coord</span> <span class="symbol">{</span>
<span class="ident">int</span> <span class="ident">x</span><span class="symbol">,</span> <span class="ident">y</span><span class="symbol">;</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">(</span><span class="ident">int</span> <span class="ident">x</span><span class="symbol">,</span> <span class="ident">int</span> <span class="ident">y</span><span class="symbol">)</span> <span class="symbol">:</span> <span class="ident">x</span> <span class="symbol">=</span> <span class="ident">x</span><span class="symbol">,</span> <span class="ident">y</span> <span class="symbol">=</span> <span class="ident">y</span> <span class="symbol">{}</span>
<span class="symbol">}</span>
<span class="keyword">class</span> <span class="ident">NamedCoord</span> <span class="symbol">:</span> <span class="ident">Coord</span> <span class="symbol">{</span>
<span class="ident">String</span> <span class="ident">name</span><span class="symbol">;</span>
<span class="keyword">oper</span> <span class="ident">init</span><span class="symbol">(</span><span class="ident">int</span> <span class="ident">x</span><span class="symbol">,</span> <span class="ident">int</span> <span class="ident">y</span><span class="symbol">,</span> <span class="ident">String</span> <span class="ident">name</span><span class="symbol">)</span> <span class="symbol">:</span>
<span class="ident">Coord</span><span class="symbol">(</span><span class="ident">x</span><span class="symbol">,</span> <span class="ident">y</span><span class="symbol">),</span>
<span class="ident">name</span> <span class="symbol">=</span> <span class="ident">name</span> <span class="symbol">{</span>
<span class="symbol">}</span>
<span class="symbol">}</span>
</PRE> <P>Now let's say we want to add some new functionality:
<UL><LI> <P>Get the distance of the coordinate from the origin (the "magnitude" of the
coordinate's vector). <LI> <P>Get the area of the rectangle defined by the coordinate and the origin.
</UL><P>In the absence of other considerations, we might just add two methods to
<TT>Coord</TT> and be done with it. However, this doesn't always work. <P>If <TT>Coord</TT> and <TT>NamedCoord</TT> are in a module we don't own (an
"external" module), adding methods is more complicated. Our new methods might
not be appropriate for general use, and for non-final classes adding new methods
breaks compatibility. So our new methods might simply not be welcome upstream,
and in any case, we might not want to be blocked on waiting for our change to
come back around into a released version of the external module. <P>We could derive a new class, "<TT>SpatialCoord</TT>", from <TT>Coord</TT> and
give it the new methods. But then <TT>NamedCoord</TT> won't have them.
Furthermore, if <TT>Coord</TT> comes from an external module, we might not even
control the allocation of the new object: it might be produced internally by
some other subsystem and merely shared with our calling code. <P>Prior to appendages, the only way to solve this was to define our new methods
as functions accepting <TT>Coord</TT> as an argument: <PRE>
<span class="ident">int</span> <span class="ident">getMagnitude</span><span class="symbol">(</span><span class="ident">Coord</span> <span class="ident">c</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">sqrt</span><span class="symbol">(</span><span class="ident">c</span><span class="symbol">.</span><span class="ident">x</span> <span class="symbol">*</span> <span class="ident">c</span><span class="symbol">.</span><span class="ident">x</span> <span class="symbol">+</span> <span class="ident">c</span><span class="symbol">.</span><span class="ident">y</span> <span class="symbol">*</span> <span class="ident">c</span><span class="symbol">.</span><span class="ident">y</span><span class="symbol">);</span>
<span class="symbol">}</span>
<span class="ident">int</span> <span class="ident">getArea</span><span class="symbol">(</span><span class="ident">Coord</span> <span class="ident">c</span><span class="symbol">)</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">c</span><span class="symbol">.</span><span class="ident">x</span> <span class="symbol">*</span> <span class="ident">c</span><span class="symbol">.</span><span class="ident">y</span><span class="symbol">;</span>
<span class="symbol">}</span>
</PRE> <P>This works, but it has a few problems as compared to having them bundled as
methods in a class:
<UL><LI> <P>As separate functions, a module using them would have to import each of them
separately and also retain them as separate elements in a shared namespace. <LI> <P>We lose some syntactic niceties, such as the <I>object</I> <B>.</B>
<I>method</I> <B>()</B> syntax and the implicit <TT>this</TT>. <LI> <P>As standalone functions, we are unable to access protected members of the
class that would be accessible to methods of a derived class. (This is not an
issue in the example, however it is an issue with the approach in general).
</UL><P>Appendages provide a nicer solution. We can define an appendage on
<TT>Coord</TT> by creating a derived class definition that uses an equal sign
("=") instead of a colon before the base class list: <PRE>
<span class="keyword">class</span> <span class="ident">SpatialCoord</span> <span class="symbol">=</span> <span class="ident">Coord</span> <span class="symbol">{</span>
<span class="ident">int</span> <span class="ident">getMagnitude</span><span class="symbol">()</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">sqrt</span><span class="symbol">(</span><span class="ident">x</span> <span class="symbol">*</span> <span class="ident">x</span> <span class="symbol">+</span> <span class="ident">y</span> <span class="symbol">*</span> <span class="ident">y</span><span class="symbol">);</span>
<span class="symbol">}</span>
<span class="ident">int</span> <span class="ident">getArea</span><span class="symbol">()</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">x</span> <span class="symbol">*</span> <span class="ident">y</span><span class="symbol">;</span>
<span class="symbol">}</span>
<span class="symbol">}</span>
</PRE> <P>Defining an appendage is very much like defining a class except that an
appendage is limited to a set of methods. These can be applied to any instance
of a class derived from the anchor class (<TT>Coord</TT>, in this case). To make
this work, an appendage can have no instance data of its own. This means:
<UL><LI> <P>No instance variables. <LI> <P>No virtual methods (all methods are <B>final</B> or explicitly
<B>static</B>). <LI> <P>No constructors or destructors.
</UL><P>To use an appendage, we must explicitly convert an instance of the anchor
class using on overloaded "<TT>oper new</TT>" (which looks like ordinary
instance construction): <PRE>
<span class="ident">foo</span> <span class="symbol">:=</span> <span class="ident">SpatialCoord</span><span class="symbol">(</span><span class="ident">Coord</span><span class="symbol">(</span><span class="number">10</span><span class="symbol">,</span> <span class="number">20</span><span class="symbol">));</span>
<span class="ident">bar</span> <span class="symbol">:=</span> <span class="ident">SpatialCoord</span><span class="symbol">(</span><span class="ident">NamedCoord</span><span class="symbol">(</span><span class="number">20</span><span class="symbol">,</span> <span class="number">30</span><span class="symbol">,</span> <span class="string">'fido'</span><span class="symbol">));</span>
<span class="ident">cout</span> <span class="ident">I</span><span class="unknown">`bar has magnitude $(bar.getMagnitude()) \
and area $(bar.getArea())\n`;
</span></PRE> <P>Note that the "foo" and "bar" assignments don't create new instances: they
just convert existing instances of <TT>Coord</TT> and <TT>NamedCoord</TT> to
<TT>SpatialCoord</TT> in order to allow the use of its methods. This is a zero
cost abstraction. <P>You can also compose an appendage from several other appendages (as long as
they all have the same anchor class). For example, we could have done this: <PRE>
<span class="keyword">class</span> <span class="ident">MagnitudeCoord</span> <span class="symbol">=</span> <span class="ident">Coord</span> <span class="symbol">{</span>
<span class="ident">int</span> <span class="ident">getMagnitude</span><span class="symbol">()</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">sqrt</span><span class="symbol">(</span><span class="ident">x</span> <span class="symbol">*</span> <span class="ident">x</span> <span class="symbol">+</span> <span class="ident">y</span> <span class="symbol">*</span> <span class="ident">y</span><span class="symbol">);</span>
<span class="symbol">}</span>
<span class="symbol">}</span>
<span class="keyword">class</span> <span class="ident">AreaCoord</span> <span class="symbol">=</span> <span class="ident">Coord</span> <span class="symbol">{</span>
<span class="ident">int</span> <span class="ident">getArea</span><span class="symbol">()</span> <span class="symbol">{</span>
<span class="keyword">return</span> <span class="ident">x</span> <span class="symbol">*</span> <span class="ident">y</span><span class="symbol">;</span>
<span class="symbol">}</span>
<span class="symbol">}</span>
<span class="keyword">class</span> <span class="ident">SpatialCoord</span> <span class="symbol">=</span> <span class="ident">MagnitudeCoord</span><span class="symbol">,</span> <span class="ident">AreaCoord</span> <span class="symbol">{}</span>
</PRE> <P>There are a number of places in the Crack library that will benefit from the
use of appendages. Notably, appendages will make it possible to define
encoding-specific <TT>String</TT> classes. The <TT>String</TT> class hierarchy
(or, more properly, the <TT>Buffer</TT> class hierarchy) currently specializes
around the concept of ownership (<TT>Buffer</TT> has no ownership assumptions,
<TT>ManagedBuffer</TT> has an associated buffer and is growable, <TT>String</TT>
owns an associated (to be treated as) immutable buffer ...). All of these are
just byte buffers: there is no character concept, the user is responsible for
assuming an encoding and ensuring that the string is treated correctly with
respect to its encoding. <P>With appendages, it will be possible to define <TT>ASCIIString</TT> and
<TT>UTF8String</TT>, so instaed of having to import individual methods from the
<TT>crack.ascii</TT> and <TT>crack.strutil</TT> modules, we'll just be able to
import (e.g.) <TT>ASCIIString</TT> and then call functions like <TT>strip()</TT>
and <TT>toLower()</TT> as normal methods. <P>There are a few potential areas for improvement in appendages:
<UL><LI> <P>Implicit conversion (while generally an antipattern) would be useful here. If
we have a function accepting an appendage as an argument, there's not a lot of
value in having either the caller or the function itself do the conversion. <LI> <P>Having some way to explicitly require validation during conversion to an
appendage would be nice (especially in the case of string appendages). You can
currently define static members to do validation, but there's no way to exclude
generation of the "oper new" methods that allow a user to more naturally bypass
them. <LI> <P>It would be useful for appendages created from classes <I>derived</I> from
the anchor class to preserve the methods of the derived class. For example, when
we do <PRE><span class="ident">bar</span> <span class="symbol">:=</span> <span class="ident">SpatialCoord</span><span class="symbol">(</span><span class="ident">NamedCoord</span><span class="symbol">(</span><span class="number">20</span><span class="symbol">,</span> <span class="number">30</span><span class="symbol">,</span> <span class="string">'fido'</span><span class="symbol">))</span></PRE> above, we're losing the ability to access the <TT>name</TT>
variable from <TT>bar</TT>. It should be possible to work around this right now
by defining the appendage as a generic, though at the cost of generating
multiple instances of the appendage code.
</UL><P>Nonetheless, appendages are a feature that I have long wished for that are
very much in line with Crack's original goal of expanding upon existing concepts
in the Object Oriented paradigm in a very natural way. </body>
</html>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-61478312108411352382017-02-08T02:39:00.001-08:002017-02-08T05:42:49.131-08:00Crack 1.0 ReleasedI am pleased to announce the release of Crack 1.0!<br />
<div>
<br /></div>
<div>
This milestone has been over six years in the making. Crack is now usable for a wide variety of applications, and I've used it to build everything from quick and dirty file scanners to web applications, music software, an OpenGL FPS engine and an <a href="https://github.com/google/mawfs">encrypted filesystem</a>.</div>
<div>
<br /></div>
<div>
In keeping with semantic versioning, this release also marks the beginning of interface stability for the language. Any future 1.x releases should be backwards compatible with this one, so there's no longer any concern about the ground shifting out from under you when you write Crack code.</div>
<div>
<br />
Massive thanks to the other primary contributors: Shannon Weyrick, Conrad Steenberg and Arno Rehn.<br />
<br /></div>
<div>
Curiously, the biggest thing Crack is lacking right now is a user community, so feel free to dig in, play around and speak up. More good stuff to come :-)<br />
<br />
<a href="http://crack-lang.org/downloads/crack-1.0.tar.gz">Download 1.0</a><br />
<a href="http://crack-lang.org/">http://crack-lang.org</a></div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com5tag:blogger.com,1999:blog-8756168285763583941.post-3595062188217351172017-02-03T06:36:00.000-08:002017-02-03T06:36:36.271-08:001.0 Release and Final ClassesI've just pushed the latest code that's been sitting on my laptop. The exciting news is that after about six years of development, I'm finally preparing the 1.0 release!<div>
<br /></div>
<div>
I wanted to be announcing this about four years ago. There have been a number of reasons that I delayed it for so long, all coming down to some level of perception that the language "wasn't ready" for a 1.0 release.</div>
<div>
<br /></div>
<div>
You could still argue that it's not ready. There are a lot of things that the language lacks. But the 1.0 designation was never about indicating completeness. It was a promise of stability. 1.0 means that we won't break compatibility - your 1.0 code should continue to run until we release 2.0. This doesn't matter much to the world at large, Crack doesn't have a lot of users. But it does matter to me. I use the language quite extensively, and I don't want to have to fix all of my projects when I make changes.</div>
<div>
<br /></div>
<div>
It also matters to me in a very personal way. I've been working on this for a long time and I want to move on to other things (not that I'm abandoning Crack, quite the contrary, I plan to continue to use it and I'm already experimenting with ideas for the next major version). I have a personal need for closure on this project, and this 1.0 label does that for me.</div>
<div>
<br /></div>
<div>
In the interest of ensuring compatibility, I've started work on one more feature which may or may not make it into 1.0. The "FinalClasses" branch contains a set of changes to allow the @final annotation to be used on classes. Final classes in Crack are similar to final classes in Java: you can't inherit from them.</div>
<div>
<br /></div>
<div>
The reason this change is important for 1.0 is because it lets us reserve classes in the standard library for future enhancements without breaking compatibility. After 1.0, we can't add public or protected members to non-final public classes, because it is possible that users have derived from these classes and introduced their own members whose names would collide with those of the standard library classes.</div>
<div>
<br /></div>
<div>
The only problem is, at this point I'm not sure I care to delay the 1.0 release for this. I still need to audit the entire standard library and add @final to all of the appropriate classes. There's also the possibility that the feature may be buggy.</div>
<div>
<br /></div>
<div>
The alternative to introducing final classes is to simply accept that there won't be any new member additions to the standard library classes. We can still add new functionality, but it will have to come in the form of new classes, which will likely be final themselves so they won't have this problem.</div>
<div>
<br /></div>
<div>
I'm going to weigh the arguments for and against final classes over the weekend. On Monday, I'll either release 1.0 or delay it for a week or two while I make much of the library classes final. But either way, there will be a Crack 1.0 release in February.</div>
<div>
<br /></div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-29735892539681714462016-10-21T07:31:00.002-07:002016-10-21T07:31:40.122-07:00Crack 0.13.1 ReleasedWe are pleased to announce the release of Crack 0.13.1.<br />
<br />
This is a patch release that fixes a couple of test failures on 32-bit. It also adds some nice features to "crackdoc". Enjoy :-)<br />
<br />mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-9012264676612507232016-09-28T03:31:00.002-07:002016-09-28T03:38:16.894-07:00Crack 0.13 ReleasedWe are pleased to announce the release of 0.13 of the <a href="http://crack-lang.org/">Crack programming language.</a> <a href="http://crack-lang.org/download.html">Download here.</a><br />
<br />
In addition to several prominent bug fixes, the primary feature of 0.13 is a
complete restructuring of the HTTP server modules. As part of this, we
include the #crack.http.auth# module which facilitates the implementation of
complete HTTP application servers in the language.<br />
<br />
The language environment is currently robust enough to merit a "1.0" label.
However, since we aim to guarantee backwards compatibility for all 1.x
versions after 1.0, the current plan is to stick with major version 0 until
there is more demand for a stable interface.<br />
<br />
Enjoy :-)
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-51379182815497216382016-07-01T09:34:00.000-07:002016-07-01T09:34:49.209-07:00Crack 0.12 ReleasedI'm happy to announce the release of Crack 0.12. <a href="http://crack-lang.org/downloads/crack-0.12.tar.gz">Download the source from here.</a><br />
<br />
Release notes:<br />
<br />
<br />
<ul>
<li>Added full support for special documentation comments, created the model builder which knows how to extract them and created the "crackdoc" documentation tool.</li>
<li>Greatly improved http server support, moved it to crack.http</li>
<li>NML extensibility enhancements.</li>
<li>Convert buffer sizes from uint to uintz</li>
<li>Change alias serialization to deal with ordering issues in nested aliases.</li>
<li>Added SHA256 hashing module.</li>
<li>Added POSIX signal handling, display stack traces for fatal signals.</li>
<li>Many more small enhancements and bug fixes.</li>
</ul>
<div>
This release has been almost a year in coming, which is way too long. I had planned to make this a 1.0 release, but since no one is clamoring for API stability I've decided to retain the 0.x versioning so I can continue to evolve the language and modules.</div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-52018874514288208012016-06-28T16:30:00.002-07:002016-06-28T16:30:53.956-07:00New Website!I've finally take the time to create a real website for Crack: <a href="http://crack-lang.org/">http://crack-lang.org</a><br />
<br />
Unsurprisingly, the site is generated by a crack script. In the process of doing this, I've enhanced NML (the markup language that the Crack manual is written in) in order to support syntax highlighting. At some point I'll regenerate the manual to fit in with the new theme.<br />
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-77476096804221434442015-11-01T06:43:00.004-08:002015-11-01T06:43:40.896-08:00SSL CiphersI just checked in support for doing encryption/decryption through OpenSSL. Crack provides a wrapper library (<span style="font-family: Courier New, Courier, monospace;">crack.crypt.ssl.cipher</span>) that allows you to encrypt/decrypt using a writer, so for example to encrypt:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> import crack.crypt.ssl EVP_aes_256_cbc, EncryptWriter;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> backing := (cwd/'outfile').writer();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> out := EncryptWriter(EVP_aes_256_cbc(), key, backing);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> for (data := src.read(1024))</span><br />
<span style="font-family: Courier New, Courier, monospace;"> out.write(data);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> out.close(); # You must explicitly close (or make them go out of scope).</span><br />
<div>
<br /></div>
<div>
<br /></div>
<div>
There were a few ciphers (specifically the AES CCM and GCM ciphers) that didn't pass a round-trip test. These require some special setup that I don't feel motivated to figure out.</div>
<div>
<br /></div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-67760792922166505242015-07-22T06:27:00.000-07:002015-07-22T06:27:24.720-07:00Crack 0.11 ReleasedI am pleased to announce the release of Crack 0.11. Enhancements include:<br />
<br />
<br />
<ul>
<li>Allow importing crack.compiler outside of an annotation.</li>
<li>Fixed casting so we can now correctly cast from secondary bases and even cast across bases.</li>
<li>Added crack.protobuf.ann, which provides an annotation to allow you to expand inline protobuf messages into generated code.</li>
<li>Streamline generic serialization (only serialize file name and line number when they change).</li>
<li>Enhancements to jack and alsa modules, made alsa extension more OO.</li>
<li>Lots of smaller fixes and enhancements.</li>
</ul>
<br />
<div>
Enjoy!</div>
<div>
<br /></div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-39511381810093689492015-07-16T07:30:00.000-07:002015-07-16T10:43:30.054-07:00Moving to githubSadly, googlecode is shutting down and we needed to find a new home for Crack.<br />
<br />
I've been a long time fan of Mercurial (I think I was using it before git existed) but I seem to be in the minority in that. Most Crack contributors appear to prefer git. There's also a huge community that's developed around github. So, given that our current project hosting is going away, this seemed to be a good time to convert entirely to git and relocate to github.<br />
<br />
In truth, I've been running the project out of git for over two months now. I migrate changes to the mercurial repo on googlecode whenever I push, and I expect I will continue to do so for the foreseeable future, but the repository in github (<a href="https://github.com/crack-lang/crack">crack-lang/crack</a>) should now be regarded as canonical. Patches to the codebase should be sent as pull requests or as git patches generated by "format-patch". We will no longer accept requests to pull from a mercurial repository.<br />
<br />
Hopefully we'll get around to replacing our home page before googlecode disappears entirely.mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-73371010899718669892015-07-10T06:49:00.001-07:002015-07-10T06:49:26.979-07:00Protobuf AnnotationsWe've had a module to deal with protobuf wire protocols for a while now (crack.protobuf), but you've always had to code your message serialization by hand. Not any more!<br />
<br />
I've just checked in crack.protobuf.ann, which is an annotation that allows you to define protobuf message definitions inline and generates the appropriate code. So, for example, this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@protobuf {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> # Uncomment "debug" to emit the generated code to standard output with</span><br />
<span style="font-family: Courier New, Courier, monospace;"> # line numbers.</span><br />
<span style="font-family: Courier New, Courier, monospace;"> #debug</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> message Bar {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> repeated string name = 1;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">Generates this:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">class Bar @impl Message {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Array[String] name = {};</span><br />
<span style="font-family: Courier New, Courier, monospace;"> oper init() {}</span><br />
<span style="font-family: Courier New, Courier, monospace;"> void serialize(ProtoWriter dst) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> for (item :in this.name)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> dst.write(1, item);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> void addField(Field field) { </span><br />
<span style="font-family: Courier New, Courier, monospace;"> if (field.id == 1) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> this.name.append(field.getString());</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int cmp(Bar other) { </span><br />
<span style="font-family: Courier New, Courier, monospace;"> int rc;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ((rc = cmp(this.name, other.name))</span><br />
<span style="font-family: Courier New, Courier, monospace;"> );</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return rc;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int cmp(Object other) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if (o := Bar.cast(other))</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return cmp(o);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> else</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return Object.cmp(other);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> uint makeHashVal() { </span><br />
<span style="font-family: Courier New, Courier, monospace;"> return makeHashVal(this.name);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @static Bar makeFromField(Field field) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Bar inst = {};</span><br />
<span style="font-family: Courier New, Courier, monospace;"> field.readMessage(inst);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return inst;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<div>
<br /></div>
<div>
As protobuf generation goes, this isn't all that great. For one thing, it would be much better if we could just generate crack code from the proto compiler like everything else and then we could use the same .proto files as everything else. The implementation is also very incomplete. It only supports the int32, int64, string and bytes types (and int64 is currently broken) and it doesn't support any protobuf syntax that is even slightly advanced. That said, it still beats coding the serialization by hand.</div>
<div>
<br /></div>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-79904991120245429332015-03-30T16:52:00.001-07:002015-03-31T05:03:46.962-07:00Crack 0.10 ReleasedWe're pleased to announce the <a href="http://crack-lang.org/">release of crack 0.10.</a><br />
<br />
It has been over a year since the release of version 0.9, way longer than we had intended. But we were determined to get caching working reasonably well, and this has been a difficult feature to get right.<br />
<br />
Fixing the bugs in caching required a major overhaul of many of the internals of the executor. As a result, we now have a much cleaner, much more reliable codebase.<br />
<br />
The new release is also generally much faster. Caching produces an observable speedup, but even more significant are the gains from deferred JITting (see <a href="http://crack-lang.blogspot.com/2014/08/fast.html">Fast</a> from late last year).<br />
<br />
Caching is now enabled by default. Though we know of no bugs in it, I expect that there are still a few. If you suspect problems, try disabling it with the -K option or by setting the environment variable CRACK_CACHING to "false". Providing a snapshot of your .crack/cache directory will help us debug the problem.<br />
<br />
Enjoy the new release, and happy cracking :-)<br />
<br />mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-62862421079899457812015-02-18T05:35:00.000-08:002015-02-18T05:35:39.389-08:00I just pushed a change that fixes a long-standing problem with interfaces.
<br />
Interfaces are implemented as ordinary annotations. When the @interface
annotation is used, it expands a definition of a class derived from
VTableBase. This lets us mix the interface in with arbitrary base classes
and also lets us define a class with multiple interfaces (diamond inheritance,
where a class inherits from multiple base classes with a common ancestor
class, is not allowed in Crack except for the VTableBase class, so interfaces
can not be derived from Object which classes are by default).
<br />
We could just derive from VTableBase except that we still need the reference
counting mechanism defined in Object. For example:
<br />
<br />
<pre> class A {}
class B : VTableBase {}
class C : A, B {}
C c = {};
B b = c;
c = null;
</pre>
<pre>
</pre>
In the example above, when 'c' is assigned to null, the reference count of its
object drops to 0 and the object is deleted because B doesn't have bind and
release operators or a reference count. 'b' now points to unmanaged memory.
<br />
Part of what @interface does is to generate bind and release operators that
delegate to Object.oper bind() and Object.oper release(). But to be able to
ues these, we need a way to convert the interface to the Object that its
implementation class will be based on.
<br />
As a hack, the code used to generate a special method:
_iface_get$(Interface)Object() ($(Interface) was the name of the interface
class). This was abstract in the interface and defined in the implementation
to simply "return this," allowing us to do the conversion. But _iface_get*
had some problems because it was based on the simple class name. So:
<br />
<ul>
<li> Aliasing interfaces didn't work, because "@implements Alias" caused
_iface_getAliasObject() methods to be generated instead of
_iface_getRealClassNameObject() methods.
</li>
<li> You couldn't implement two different interfaces with the same simple name,
for example Functor1[void, int] and Functor1[void, String] (for generics,
we only used the name of the generic class, not the instantiation class).
</li>
</ul>
The solution to this is the special "oper from ClassName" operator. Like
"oper to", "oper from" is implemented in the parser and has full knowledge of
the type that is specified. Therefore, it can implement the operator based on
the canonical name of the type, solving the problems above.
<br />
I originally considered creating a more complete implementation of virtual
base classes, but with "oper from", I no longer see a use case for it.
I think that everything that you can do with a virtual base class you can also
do with "oper from" and annotations.
<br />
Of course, I'm open to a counterexample.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-83859907954544933002014-08-07T03:52:00.003-07:002014-08-07T03:52:57.737-07:00FastA long-standing goal of the Crack language has been to produce a system that is fast. Specifically, we wanted to minimize the code-test cycle. The language has thus far fallen short in this respect. Startup times for anything less than very small programs have tended to be over five seconds.<br />
<br />
We were never able to obtain any solid conclusions from profiling the code, but we knew there was a lot to be gained from caching. So over two years ago we started work on caching. Needless to say, this was a harder problem than we imagined.<br />
<br />
Caching is simply storing the artifacts of a successful compile so that we don't have to produce them again. In theory, the work involved in fully parsing and validation the source as well as generation and optimization of LLVM IR code is greater than the effort involved in simple deserialization of these structures.<br />
<br />
Getting it to work right has been very difficult, largely because of a number of shortcuts and bad design choices that I made while producing the original compiler. My first reaction to this was, of course, to try to adapt caching to the existing code. However, when these attempts failed I did finally do the right thing and make the big changes to the design that were necessary to get caching to work.<br />
<br />
And now, finally, it does. I can run code, make changes, and run again with the most complicated programs that I have and everything just works. The modules for the changed code and all of their dependencies get rebuilt, everything else gets loaded from the cache. Sweet! (I'm sure there are still some bugs in there somewhere...)<br />
<br />
So trying this out against the most complicated program that we have -- the "wurld" game engine demo in 'examples' -- without any cached files, takes 12 seconds to build on my laptop. After caching, it takes ... 9 seconds.<br />
<br />
9 seconds? Really? A 25% reduction after all of that work? That's depressing. So I did some more benchmarking.<br />
<br />
One of the results of the restructuring work required for caching is that all of the jitting of a cached program now happens at the end, just before the program is run and after all of the modules are loaded from the cache. Originally we jitted every module when we finished loading it. The new structure makes it much easier to see how much time we're spending on jitting versus everything else.<br />
<br />
It turns out, we were spending most of that time, 7-8 seconds of it, on jitting. <br />
<br />
We were storing the addresses of all of our functions before running everything. We need function addresses in order to generate source file and function names when reporting stack traces. But in the course of looking all of these addresses up, we were also generating all of the functions in the program, whether we needed them or not.<br />
<br />
LLVM's ExecutionEngine lets you watch for notifications for a number of different internal events. In particular, it lets you get a notification when a function gets jitted. So I replaced the registration loop with a notification callback. Now instead of function registration driving jitting, jitting drives function registration, and only for the functions that are used by the program. This got us down to about 5 seconds total runtime.<br />
<br />
The ExecutionEngine also lets you enable "lazy jitting." By default, when you request a function address, that function and all of its dependencies get jitted. By contrast, lazy jitting defers the jitting of a function until it is actually called. Enabling this feature brought the total run time down to under 2.5 seconds, because the hacked version of "wurld" I was using for benchmarking was loading everything and doing initialization but then immediately terminating, so much of the code is never called anyway.<br />
<br />
I'm not sure if there's anything more we can do to improve on this, but 2.5 seconds is well in the realm of tolerable.<br />
<br />
It's somewhat embarrassing that the huge effort of caching yielded only a small amount of the initial gains while an hour or two of investigation and simple tweaking had such a big impact. But on the other hand, the simple tweaking couldn't have worked without some of the changes we put in for caching. And as it turns out, post-tweaks, caching ends up saving us 60% of the startup time, which is huge.<br />
<br />
Going forward, after we release 1.0, I still want to start to experiment with alternate backends. libjit, in particular, looks like a promising alternative to LLVM for our JIT backend. But as it stands, in terms of performance, I think we're in pretty good shape for a 1.0 release.<br />
<br />mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-74131458491371259132014-02-18T14:59:00.003-08:002014-02-18T15:04:45.638-08:00Crack 0.9 ReleasedWe are pleased to announce the release of Crack 0.9. The only major user-visible change in this release is the introduction of support for threads. We've also done a great deal of work towards caching, but unfortunately this feature is still not ready for general use.<br />
<br />
Other, lesser features include an IRC module (crack.net.irc) and a protobuf module (crack.protobuf).<br />
<br />
Please note that the new tarball is not available on the googlecode download page: new uploads have been disabled by Google. Our downloads are now available at http://crack-lang.org/downloads/<br />
<br />
Enjoy!<br />
<br />mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-87937450753263177902014-01-23T03:58:00.000-08:002014-01-23T03:58:39.044-08:00ThreadsI'm happy to say that Crack now supports threading. Thread support required two basic ingredients: a pthread extension (wrapped in a high-level Crack module) and the atomic_int type for reference counting.<br />
<br />
Normal integer operations are not sufficient to support reference counting in a multithreaded environment. Compilers and CPUs perform all kinds of tricks in order to improve performance, and this can result in two different threads seeing two different values for the same variable at any given point in time. Atomic operations solve this problem. They prevent the compiler from doing any special tricks to elide or reorder the operation, and require the CPU to lock the bus and synchronize the operation across all views of memory.<br />
<br />
To expose atomic operations in the language, I've created an atomic_int type which supports a limited set of integer operations (mainly += and -=) and synchronized conversion to plain integer types. The reference count of crack.lang.Object is now of type atomic_int, giving us atomic reference counts.<br />
<br />
For actual thread creation and more general synchronization, I've implemented the crack.threads module. This provides Crack classes encapsulating functions from a new pthread extension, so we have Thread, Mutex and Condition classes. There is also a higher level Queue generic which provides one of the most common modes of inter-thread communication.<br />
<br />
The new threading code is currently available only from the repository, but we're about due for a release, so it should be available soon in version 0.9 of the crack SDK. <br />
<br />mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-9904977334878717612013-10-08T09:55:00.000-07:002013-10-08T09:55:27.357-07:00Crack 0.8 ReleasedWe're pleased to announce the release of Crack 0.8. The new release includes <br />a number of bug-fixes and code cleanups as well as a number of new extension <br />modules, and brings us up to date with LLVM 3.3.<br /><br />It's been almost a year since our last release, which is far longer than usual <br />and far longer than what we'd like. The reason for the delay has been the <br />ongoing work on module caching. Module caching provides a substantial <br />speed-up of program loading by allowing the executor to reuse the <br />artifacts of previous compiles instead of recompiling everything from source. <br />Unfortunately, it has proven to be very difficult to get this feature working <br />perfectly, and it still doesn't work quite right for complicated generics. <br />Users are encouraged to experiment with it by adding the -C option.<br /><br />The complete release notes for 0.8 follows:<br /><br /> - Lots of bug fixes and small features.<br /> - Lots of refactors and code cleanups.<br /> - Implemented most of the code for caching (which is still way too buggy <br /> for anything other than experimentation).<br /> - Added flag driven tracing facility.<br /> - Lots of new modules and extension modules:<br /> - OpenSSL<br /> - libpng<br /> - alsa, midi, jack, and fluidsynth<br /> - curl<br /> - SHA1 digests<br /> - base64 encoding<br /> - Mongo DB and LMDB<br /> - netCDF<br /> - Mersenne Twister PRNG.<br /> - enhanced the test framework to support composite tests.<br /> - added the Wurld OpenGL example program.<br /> - Ported to LLVM 3.3<br /> - Changed annotation-in-generic semantics.mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0tag:blogger.com,1999:blog-8756168285763583941.post-90784865256574136162013-09-10T07:56:00.000-07:002013-09-10T07:56:02.716-07:00Annotation Semantics Changing for Generics Annotations are a useful feature that essentially allow you to program the Crack compiler at compile time. They provide the functionality of macros in C plus a whole lot more - you can actually use them to implement your own domain specific languages, if you like.<br />
<br />
Annotations are stored in a "compile time namespace." This is separate from the normal namespace that functions, variables and classes live in, but it follows the same resolution rules: annotations are scoped to the lexical scope in which they are defined.<br />
<br />
Until now, annotations used in generics were no different from annotations in any other context. When the generic was instantiated with new parameters, it was essentially replayed into the same compile time context (including the same compile-time namespace).<br />
<br />
Unfortunately, this approach doesn't work with caching. When a generic is cached, the original compile context is gone. We have to restore parts of that context (notably, the normal namespace) but the contents of the compile time namespace cannot be persisted or restored: it can contain arbitrary objects created by the annotation system, and, in fact, it routinely contains pointers to primitive functions.<br />
<br />
The only way to restore the compile namespace of a generic is to replay the original source file it was defined in. This would be contrary to the purpose of caching, and it would also require us to create a dummy environment so as not to actually regenerate existing code and representational datastructures.<br />
<br />
Rather than try to go down this path and further delay the 1.0 release, I've decided to impose some limitations on the way that annotations can be used with generics. This was a painful decision: I don't like having non-uniform semantics in the language. Annotations should work the same for generics as for any other code in a module, but something had to give and after discussing it with the team I feel this is the best compromise.<br />
<br />
As of this morning's check-in, generics now preserve only imported annotations. So for example, the following code will no longer compile:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@import crack.ann define;</span><br />
<span style="font-family: Courier New, Courier, monospace;">@define my_func() { void f() {} }</span><br />
<span style="font-family: Courier New, Courier, monospace;">class A[T] { @my_func }</span><br />
<br />
It could be rewritten like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@import crack.ann define;</span><br />
<span style="font-family: Courier New, Courier, monospace;">class A[T] {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">@define my_func() { void f() {} }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @my_func</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Note that the symbols defined with </span><span style="font-family: Courier New, Courier, monospace;">@import</span><span style="font-family: Georgia, Times New Roman, serif;"> </span><span style="font-family: inherit;">can be reused -- it's possible for us to replay imports safely. But macros defined with </span><span style="font-family: Courier New, Courier, monospace;">@define</span><span style="font-family: inherit;"> must be defined (or redefined) within the scope of the generic itself.</span><br />
<br />
<blockquote class="tr_bq">
</blockquote>
mindhoghttp://www.blogger.com/profile/07042202216138895039noreply@blogger.com0