Thursday, July 7, 2011

Classes and dynamic typing

Designing PineDL class system is proving to be harder than I expected.

There are a few things to consider when designing a class system: Inheritance, access modifiers, scopes, nested classes, virtual members, etc.

Inheritance can be fairly straightforward, at least in a statically typed programming language. In fact, inheritance can be easy to implement even in dynamically typed languages. Multiple inheritance can be harder, but it's still not that hard. Provided that you can figure out at compile time what the base class(es) is/are, things are simple enough.

Now, let's add access modifiers and scopes to the mix.
Initially, let's consider only two access modifiers - public and private.
Public is very easy to implement. Private can be more complex. First of all, we need to define what private means. One way to define it is a member that can only be accessed from a scope that's descendant of the class scope it is declared in.
In statically typed languages, this is easy enough.
However, consider this hypothetical situation in pseudo-code:
class Foo {
private var x;
public function bar(othervar) {
this.x = othervar.x;
}
}
Can we do this?
Let's say this language is statically typed and othervar is of type Foo. Then sure we can. The scope of bar is inside the scope of Foo, which is the type of othervar.
Now, let's say this is a dynamically typed language. We can not, at compile time, know if othervar is Foo or not. In addition, we don't know if othervar.x is private or public.
This means that, at runtime, we have to find out if othervar.x is private, and if it, we must find out if Foo has permissions to access it private othervar members. This may not be trivial.
But it gets worse.
Let's add protected to the mix. Protected members also allow access from derived classes, so it gets harder to check.
Let's say we define that protected members of a class can also be accessed from nested classes of derived classes. This makes sense, but only makes things even harder.

Finally, virtual members. Class Derived extends Base. Base defines a virtual member virtualfoo and Derived overrides it.
Let's consider the following code in a hypothetical statically typed language:
Base bar = new Derived();
bar.virtualfoo();
In the above case, because virtualfoo is virtual, Derived.virtualfoo is called.
In a dynamically typed language, the exact same thing happens, without any problem nor ambiguity.
Also, even in this case, the Base.virtualfoo must still exist somewhere in case Derived does something like "base.virtualfoo()"(super.virtualfoo in Java).

Now, what about members which aren't virtual?
Base bar = new Derived();
bar.nonvirtualfoo(); //Where nonvirtualfoo is defined in both Base and Derived.
Some languages may not allow the above to begin with. C# allows it, but includes a keyword "new" to ensure it is intentional.
In a dynamically typed language, this can be implemented, but even if it works, it wouldn't be intuitive.

Now, if both Base and Derived include a nonvirtualfoo() member, but Base's is private and the one in Derived is public, then it would make more sense, but still be problematic.

Here's what I thought so far:
1. Classes are important to have and so is inheritance
2. The public access modifier and virtual members are in.
3. The private access modifier and non-virtual members are at risk.
4. The protected access modifier is out.

One thing I thought, inspired by some JavaScript programming, would be to have - instead of private - something even more private. Some sort of instance-private, that could only be accessed with the "this" keyword. And perhaps some sort of inherited-private, that could be called also with the "super"/"base" keyword.

I haven't decided this yet, but it's clear that a conventional class/access modifier would not be intuitive nor efficient in PineDL. These are just some ideas on how to solve the problem.

Monday, February 28, 2011

Introducing PineDL 1.0a3

It has been a while since the last alpha, but today I am proud to announce a new alpha release of the PineDL compiler.

Besides some source code cleanup and code quality improvements(including some gendarme warnings fixed and basic unit testing), here are some of the new features:

1. The result of ++a/--a is now stored to a. Previously, this was evaluated as being pretty much the same as (a+1).
2. Added support for a[0]++ and ++a[0].
3. Implemented "for" statements
4. CompilerUtils, a new library designed to simplify compilation and execution of PineDL code.
5. The ability to execute a PineDL program and actually read the returned code. Previously, one could only call the main function and there was no way to check the return codes.
6. Added support for named while/for statements. This is a feature of languages such as Java and a notable lacking feature of C++. Of course, this is pretty much useless since there are no break/continue statements yet.
7. Added support for assignments like a=b, or even a,b=b,a. The second example would swap the contents of a and b, something that's really simple in PineDL.
8. Improved compatibility with Microsoft .NET(rather than just being Mono compatible).

There is still a lot of work to do. Here are some of the features I'll try to have implemented in alpha4.
1. do...while statements
2. break/continue, including named break/continue.
3. a,b = function_call();
4. a.b.c.d = foo;
5. class bar {}, including perhaps inheritance
6. Character constants('x', '\n', etc.)

Binary and Source code available.