|
|
|
|
Quick Links
Understanding XL
In depth
Other projects
|
XLR: Extensible Language and Runtime
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
XL, an extensible programming language, implements the ideas of Concept Programming.
If you want to know more, you should start here.
In addition to the constructors work and various other cleanup, I've also been attempting to bring the Java tests in line with the C tests. This has proven relatively difficult, because Java is not a very practical language as a target of code generation: no pointers, no unsigned types, ... Another problem I'm having now is how to bring back the work I did from the git into Subversion. It turns out that git-svn is unable to follow the majority of branch merges done by the git. This makes it unable to follow complex branch histories, and you have to "squash" the work you did on a branch into the branch you will use for Subversion commits. That is annoying, as it loses a lot of the history, which was the primary benefit I was seeing in this approach. I hope that I will not run into the problem if I avoid cross-branch merges, but this is not entirely clear. In any event, I now have a relatively large set of git history that is tricky to merge back. I'm losing a lot of history data in the process, which is unfortunate.
I had a long week of vacation, which we spent mostly around home. That was a good time for doing some XL development, and I started attacking a couple rather tough nuts, bugs that had annoyed me for a while. Two of them made it difficult to implement complex numbers the way I wanted. The problem was, put simply, how to initialize a field to zero. How hard can that be? Well, consider that the complex type is generic and depends on a number type. That number type can be integer or real for example (although you could consider intervals and any other kind of fancy possibility). Now, if I'm writing the constructor for complex taking a single value, it's going to look something like:
function Complex (re : complex.value) return complex written re is result.re := re // result.im := 0.0 If I write result.im := 0.0, then instantiation will fail when instantiating complex with integer. Conversely, result.im := 0 will not work for real, because XL has no implicit conversion from integer to real (although you can add one easily). So there are two solutions, neither of which worked correctly. The first one was to leave the code as above, without an initializer, and rely on some kind of default initialization semantics inside constructors. The problem with this solution is that such initializers did not exist. The second solution was to add some new notation that would allow me to explicitly call a constructor, something like:
function Complex (re : complex.value) return complex written re is result.re := re result.im := complex.value(0) Now, it's an explicit call to a constructor, and there is no problem with real(0). There are cases where this second solution is the only one (e.g. the default constructor doesn't work for you). That was actually a pretty large change set. I embarked into doing that, but decided that I would do that in the GIT to avoid corrupting the SVN database. That way, I could keep multiple work branches, etc. For an introduction on how to use the GIT with SVN, see http://tsunanet.blogspot.com/2007/07/learning-git-svn-in-5min.html. The GIT works pretty well for that, and I was really happy... ... Until the point where I wanted to commit to Subversion. I used git svn dcommit as the blog says. Things started rather well, see revisions after Revision 381... The problem is that I had made a mistake initially, and added some LLVM code that was not ready for prime time. The GIT somehow tried to check-in into SVN a .svn directory, wrecking havoc. It took me a good 45 minutes to sort out the mess on both sides, but I think that I'm back on track. I lost a lot of the history on the SVN side, though, having one big massive check-in at the end with the end result instead of the individual steps. There is other work that I did during that vacation time that I want to commit to Subversion too, but I will first revisit it to check that it's safe, i.e. that I did not commit .svn files anywhere...
Added support for function pointers in Revision 370. The real problem was support for overloading, as illustrated in this test, reproduced below:
In that example, the problem is with Invoke Foo, which needs to be able to decide which Foo is to be selected (the first one in that case).
Based on feedback from many people (most notably Daveed Vandevoorde and Lionel Schaffhauser), I posted a new presentation about Concept Programming. This should make the ideas much easier to grasp. During the discussion, Daveed Vandevoorde pointed me to a very interesting paper about memory transactional models, which he used as an argument in favor of functional programming. Recommended reading, even if I don't think that this is a point for functional programming at all myself. Lionel Schaffhauser pointed out a number of presentation-related issues, which prompted me to change the order of the slides and add a whole section about the "Maximum" example. As a reminder, there is also an older presentation about XL itself. Blog post about this presentation.
I finally posted a slideset about concept programming that had been rotting on my hard disk for way too long... This gave me an opportunity to re-read older articles on these topics, one I had written for Dr Dobb's Journal, and another one written by Martin Heller (Mr. Computer Language Person) in Byte.
With Revision 338, XL now has basic support for enumerations. Not a big deal as far as features are concerned, but it allowed me to figure out a long-standing bug in the treatment of named types that had prevented alternate X.Y translations from working right.
While writing code for pointer modules, and specifically XL.POINTER.MACHINE_ADDRESS, it occured to me that I had a problem with the following code:
function Pointer(addr : integer) return pointer is XL.BYTECODE.int_to_ptr The problem is that the intended usage, as illustrated in this example, would be something like:
Machine_Register : pointer to unsigned := Pointer(16#FF_FC0A) The problem with this is that none of the arguments to Pointer helps figuring out what particular generic parameters for the the return type are (i.e. in this case, pointer to integer, or pointer to real, or something else). I tried to wiggle out of this, because I know that C++ (the only mainstream language that massively implements automatic deduction in templates, since Ada for example requires explicit instantiation) does not implement return type deductions. There are good reasons for that: defining precisely how it works is hard. Ada does have return-type overloading, which is a somewhat similar problem, and it is known to be expensive. But ultimately, I had to concede, on concept programming grounds that there was simply no good alternative. So I ended up hacking together what seems to be the simplest, least expensive semantics allowing these particular examples to work. By "simplest and least expensive", I mean in particular that it works only at one level, and only if other parameters of the written form or function call entirely define the generic type being returned. But apparently, it now works to some extent.
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright 2008 Christophe de Dinechin (Blog)
E-mail: XL Mailing List (polluted by spam, unfortunately)