Saturday, April 30, 2005

More about constants

Constants implementation finished... It has been hard, because Freya must admit this kind of declarations:
const Pi = 3.14;
It is the constant type what's missing in this example, as it happens in Pascal. C# always requires the type declaration:
public const double Pi = 3.14;
Of course, Freya also admits this syntax:
const Pi: Double := 3.14;
The problem with implicit types in constants is that you face two challenges at the same time: finding the data type and then, evaluating the expression. It's already solved, but it could have been easier without this kind of declarations.

Labels:

Friday, April 29, 2005

Constant symbols

I'm working right now in the implementation of constant symbols. This is how constants are declared in Freya:
MathHelper = class
public
const Pi: Double := 3.141592653589;
const E = 2.718281828459;
end;
Constant can be declared inside a method implementation too:
method TrySave;
const
MAX_ATTEMPTS = 3;
begin
// ...
end;
Local constants are easy to implement, since they only exist at compile time, and member constants don't use them in their own definitions. On the other hand, member constants require a careful implementation. The expression in a constant declaration may contain references to other constants, as long as these references don't cause circular dependences. This is a simple example:
Trigonometry = static class
public
const PiOver2 = MathHelper.Pi / 2.0;
// ...
end;

MathHelper = class
public
const Pi: Double := 3.141592653589;
// ...
end;
I think I'll handle constant definitions right before performing "body resolution" on the Abstract Syntax Tree. Probably, I'll gather all constants from the compiling project in a single list, to execute a topological sort on this list. I have a vague idea about a brute force algorithm for topological sort, but I'm afraid I'll have to check my copy of The Art of Computer Programming for a better approach.

Labels:

Raison d'être

There are a lot of programming languages already running in the .NET Framework. The CLR leaves almost no freedom to the designer of the object model. The "official" .NET languages are quite good and comprehensive. If you enjoy curly braces and esoteric operators, C# is your language. If you hate curly braces, you could choose a face lifted VB.NET, with its new support for operator overloading and generic types. Is there any chance for Freya in this hard competition?
First of all, don't get fooled: VB.NET is still a line oriented language, and that's not a minor issue. Though the newest VB.NET has almost nothing to do with Vintage Basic, I think it's not a real alternative for those, like me, who prefer a language inspired in the Algol family. The natural alternative should have been Delphi, a language also designed by Anders Hejlsberg but, alas, Borland decided that Delphi.NET should keep the compatibility with existing "native" Delphi code, and the result is a hybrid scaring monster.
Freya has, indeed, a winning card in the sleeve: it has been designed for .NET v2.0. You can spell it this way: Freya supports generic types since its first version, and this allows a more sound and complete type system. For instance, Freya array types are no longer special types in any sense: they are just closed generic types built over a mythical generic Array[X] class. I say "mythical" because there's no such class in the CLR: System.Array is a non generic class. Another example? Take the retorted syntax for managing delegate types in .NET v1.x languages:
new EventHandler(button1_Click)
There you have a constructor using a non existing type: what's the type of the constructor parameter? Sure, it is a "method group". Could you use a "method group" elsewhere in your own classes? No, you can't. It's true that C# v2.0 has simplified this syntax, so you could omit the explicit constructor call. In Freya, you can always use a method name as it were a delegate type value.
Also, there are several minor syntactic details favoring Freya, but I will only mention one of them here: the distinctive marker for class members, a common feature in the Algol/Pascal family languages:
method DoThis(UsingThis: Integer);
method ReturnThat: String;
// The class name may be ommitted
constructor MyClass;
destructor MyClass;
iterator LoopOverThis: DataRow;
On the contrary, C/C++/C# has to fiddle with a cryptic and limiting syntax that imposes serious limitations in C# and even in the old good C++. How do you write a destructor in C++/C#?
~ MyClass() {}
This is probably the ugliest thing in language design you will ever meet! And how C# manages to declare an iterator? Actually, there is not such a thing in C#! Sure, we have something called "iterator blocks". How do we identify an iterator block? Well, you must read the whole block looking for yield statements. Nice, huh? And then, you have to tell between yield break and yield return. Now, let's see an iterator in Freya:
// This is real code, drawn
// from the Freya's compiler

iterator Members[X(AstMember)]: X;
// A generic iterator, with a
// base class constraint in the
// generic type parameter.
begin
for M: AstMember in AllMembers do
begin
Result := M as AstMember;
if Result <> nil then Yield;
end;
end;
Of course, there are more reasons than those I have presented here. For instance, I'm fond of the Freya solution for class declarations/implementations and the whole attitude I call "just an implementation detail". But there's a time and a place...

Labels: , ,

Thursday, April 28, 2005

Implementing interface mappings

Freya has three techniques for implementing interface types:
  1. Implicit implementation: a public method in the class with the proper signature.
  2. Explicit implementation: an implicitly private method, with a compound name including the interface type name and the interface method name, just as in C#.
  3. Implementation by delegation: this is a feature borrowed from Delphi. It’s a simple but effective technique for reusing implementations, and it makes easy to change the behavior of an instance by plugging a different implementation, at runtime.
I'll show you an example of implementation by delegation:
using System, System.Collections;
public
// All Foo features are private
Foo = class(IEnumerable)
end;

implementation for Foo is
// A private instance field.
var Items: Array[String] = ['Freya', 'rules'];

// Just an implementation detail!
interface IEnumerable = Items;

end.
In this example, all calls to methods from IEnumerable methods are dispatched to the implementation of IEnumerable already available in Items. This is possible because there’s an implicit conversion from any array type to IEnumerable.
Native Delphi implemented this feature with a clever trick, by modifying the typecast operation. Our current implementation is probably not as efficient as native Delphi’s one, but it’s easy to code. When an interface delegation is found by the compiler, it synthesizes the required methods in the implementing class. Since these are very short methods, chances are high that the CIL loader will translate them as inline method calls.
We are trying another complementary solution: whenever possible, those method thunks call the target implementation using “tail calls”. Tail calls are supported by the CIL through an instruction prefix that can precede the “call” and “callvirt” operation codes. This prefix instructs the CLR to discard the current stack frame before jumping to the target method. There are no guarantees that this hint will be honored by the CIL loader, however. We still have to run the corresponding benchmarks before deciding the best translation for this useful feature.
Update: I didn't realize then, but tail calls have no effect when performed on virtual methods, so, after some tests, this "optimization" was discarded.
By the way, tail calls are only generated when the method signature does not include any reference or out parameters. That’s because a reference could point to a variable in the current stack frame, so the CLR has no way to verify whether a given call is safe or not. When all parameters are passed by value, tail calls are considered a safe operation.

Labels:

Freya says Hi!

Hello World!
This blog is dedicated to the Freya Programming Language, a new object oriented language specially designed for running on the .NET Framework, version 2.0 and higher, when available.
In the next few days, I'll post more information about Freya features and, mainly, about its ongoing implementation. I will appreciate any comments, suggestions and proposals.
Freya is a join effort by Moebius Ootics (www.moebiusootics.com) and Intuitive Sight, a.k.a IntSight (www.intsight.com), my own company.
Best regards, and keep in touch!
Ian Marteens