Version 0.6.1 released
Normally I start these update posts with some comment about how much has changed, or how long it’s been since the last one. Sadly, I can’t think of anything to say so let’s just jump right into some key changes:
Method improvements
Methods are a really powerful way of writing functions which can handle all sorts of data types. That being said, they are not without their problems and so we’re always working to improve them. One issue is the large increase in code size that using methods results in. In Urn 0.6.1, we’ve tried to lower that overhead, resulting in even smaller files!
Alongside with that, we’ve also added the ability to specify wrappers within methods. Every call to your method will go
through this delegate, allowing one to provide specialist logic. This is used by the eq?
method to check using the
==
operator before trying anything else.
(defgeneric eq? (x y)
"Compare values for equality deeply."
:delegate (lambda (x y)
(if (= x y)
true
(myself x y))))
Code generation and optimisation tweaks
Interestingly enough, method delegates exposed several places where code generation could be further improved. One such
improvement was forcing bindings to be generated as local
definitions rather than directly called functions. This
makes code more readable and potentially allows further improvements as statements can be emitted more sensibly. For
instance, consider the following code:
(print!
(with (foo (if (empty? '()) 1 2))
(+ 1 foo)))
here’s how it would be compiled on 0.6.0:
return print1(1 + (function(foo)
return foo
end)((function()
if empty_3f_1({tag="list", n=0}) then
return 1
else
return 2
end
end)()))
and here’s the equivalent code on 0.6.1:
return print1(1 + (function()
local foo
if empty_3f_1({tag="list", n=0}) then
foo = 1
else
foo = 2
end
return foo
end)())
Another interesting optimisation we now apply is lowering “deferrable” variables. For instance, consider this definition:
(with (foo '())
(when (empty? '())
(debug foo)))
The definition of foo
is only needed if then when
block is executed, and so we’re able to “push” the definition
down:
(when (empty? '())
(with (foo '())
(debug foo)))
Whilst this code doesn’t appear much in practice (or at least in this overly simplistic form), it’s nice to catch the few occasions where it does.