Tuesday, February 26, 2008

Defining mutually recursive classes in F#

While working in some F# code I learned that the definition of classes that refer to each other require a special syntax. For example, if you write the following code:


type Type1() =
class
let mutable m : Type2 Option = None
member this.foo(x : int) =
1
end

type Type2() =
class
let mutable m : Type1 Option = None
member this.goo() =
1
end


You will get a compiler error saying that: The type 'Type2' is not defined in the first use of Type2.

As explained in Adventures in F#--Corecursion defining mutually recursive functions requires the use of the and keyword between function definitions. As briefly mentioned in the Type Definitions section of the manual, the and keyword can also be used in types.

So the solution for defining the above example looks like this:


type Type1() =
class
let mutable m : Type2 Option = None
member this.foo(x : int) =
1
end
and Type2() =
class
let mutable m : Type1 Option = None
member this.goo() =
1
end


It is important to note that this syntax must be used also when mutual class references occur in method arguments or local definitions, for example:


type Type1() =
class
member this.foo(aType2 : Type2) =
1
end
and Type2() =
class
let mutable m : Type1 Option = None
member this.goo() =
1
end

Monday, February 18, 2008

Two ways of defining classes in F#

While reading documentation about F# I learned about two ways for defining classes.

In F# you have several options for defining data structures including records, discriminated unions and classes . A nice resource for learning about the syntax of class definitions is Object Model Syntax Examples also F# Overview (III.) - Imperative and Object-Oriented Programming and the F# Manual: Class definitions provide more information.

The first way of defining classes defines the object construction parts explicitly:


type Shape = class
val x : int
val y : int

new(aX,aY) =
{ x = aX ;
y = aY }

override self.ToString() =
string.Format("({0},{1})",self.x, self.y)

end

type Square = class
inherit Shape as baseClass
val side : int

new (aX,aY,aSide) = {
inherit Shape(aX,aY) ;
side = aSide
}

override self.ToString() =
string.Format("{0} -- {1}",baseClass.ToString(), self.side)
end




The second way uses implicit construction:


type Shape(x : int,y : int) = class
override self.ToString() =
string.Format("({0},{1})",x, y)

end

type Square(x : int,y : int,side : int) = class
inherit Shape(x,y) as baseClass

override self.ToString() =
string.Format("{0} -- {1}",baseClass.ToString(), side)

end

Wednesday, February 6, 2008

Handling a call to a missing method in different languages, Part 2

This is the second of a two-part series of posts about the way different languages allow you to handle a call to method that doesn't exist. For this part I'm going to show Python, Objective-C, Haxe, ActionScript and Perl . At the end a note on languages not covered.


Python

In Python, this feature is available by implementing the __getattr__(self, name) method. This method is used to handle the access to a attribute.

The CsvFileEntry class code looks like this:


class CsvFileEntry(object):
def __init__(self,headers,contents):
self.headers = headers
self.contents = contents

def __getattr__(self, name):

if (self.headers.has_key(name)):
return self.contents[self.headers[name]]
else:
raise AttributeError,name



The implementation of CsvFile is the following(without the file loading part):


class CsvFile(object):
contents = []
headers = {}
def __init__(self, filename):
...

def entries(self):
for e in self.contents:
yield CsvFileEntry(self.headers,e)


A use of these classes:


f = csvfile.CsvFile('testfile.csv')
cars = csvfile.CsvFile('cars.csv')


for e in f.entries():
print "%s , %s\n" % (e.Name,e.Age)

for e in cars.entries():
print "%s , %s\n" % (e.Model,e.Year)


As someone commented in the previous post, __getattr__ could also return a function. A nice example of this is available here: Python's getattr.

Objective-C

The method forwarding capabilities of Objective-C could be used to implement this feature.

For this example I'm using GNUstep. A nice description of the forwaring mecanism using GNUstep is available from its documentation: 5.3 Forwarding.


The definition of the CsvFileEntry class is the following:

Declaration:



#include <Foundation/Foundation.h>

@interface CsvFileEntry: NSObject
{
NSArray* entryContents;
NSDictionary* headers;
}
- (id)init:(NSArray*)contents headers: (NSDictionary*)theHeaders;
- (NSString*) getField:(NSString*)name;
- (void) forwardInvocation: (NSInvocation*)invocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;

@end


Implementation:


@implementation CsvFileEntry

- (id)init:(NSArray*)contents headers: (NSDictionary*)theHeaders
{
entryContents = contents;
headers = theHeaders;
}

- (NSString*) getField:(NSString*)name
{
if ([headers objectForKey: name] != nil) {
NSNumber* index = [headers objectForKey: name];
NSString* result = [entryContents objectAtIndex: [index intValue]];
return [entryContents objectAtIndex: [index intValue]];
} else {
return nil;
}
}

- (void) forwardInvocation: (NSInvocation*)invocation
{
NSString* a = NSStringFromSelector([invocation selector]);
[invocation setArgument: &a atIndex: 2];
[invocation setSelector: NSSelectorFromString(@"getField:")];
return [invocation invokeWithTarget:self];

}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
if([headers objectForKey: NSStringFromSelector(sel)] != nil) {
NSMethodSignature* sig;
sig = [[self class]
instanceMethodSignatureForSelector:
NSSelectorFromString(@"getField:") ];
return sig;
} else {
return [super methodSignatureForSelector: sel];
}

}
@end


The methodSignatureFromSelector method returns information about the method to be invoked. Here what we do is to return the information of the getFieldMethod. The forwardInvocation method forwards the invocation to the getField method and sets the name of field as its first argument (arguments starts at index number 2).


The implementation of the CsvFile class is the following (without the file loading part):


@interface CsvFile: NSObject
{
NSArray* contentsData;
NSDictionary* headers;
NSString* fileName;
}
- init: (NSString*)filePath;
- (NSArray*) entries;
@end



@implementation CsvFile
-init: (NSString*)filePath
{
...
}

- (NSArray*) entries
{
int contentsSize = [contentsData count];
NSMutableArray* entriesArray = [NSMutableArray arrayWithCapacity: contentsSize];

int i;
for(i = 0;i < contentsSize;i++) {
[entriesArray
addObject:
[[[CsvFileEntry new]
init: [contentsData objectAtIndex: i]
headers: headers ]
autorelease]];
}
return entriesArray;
}
@end


A use of these classes is the following:


...
CsvFile* csv = [[CsvFile alloc] init: @"testfile.csv"];
CsvFile* cars = [[CsvFile alloc] init: @"cars.csv"];

int i;
NSArray* entries;
NSLog(@"--------------");

entries = [csv entries];
for( i = 0;i < [entries count];i++)
{
CsvFileEntry* entry = [entries objectAtIndex: i];
NSLog(@"Name: %@ Score: %@",[entry Name], [entry Score]);
}

NSLog(@"--------------");

entries = [cars entries];
for( i = 0;i < [entries count];i++)
{
CsvFileEntry* entry = [entries objectAtIndex: i];
NSLog(@"Model: %@ Year: %@",[entry Model], [entry Year]);
}
...


A nice experiment will be to try this code in a Mac environment.

Haxe

Haxe is an interesting language that comes with a compiler with backends for Javascript, Flash and the Neko virtual machine. Haxe provides this functionality with the __resolve method a description of this mecanism can be found here: missing_method, the haxe way.

The implementation of the CsvFileEntry class is the following:


class CsvFileEntry implements Dynamic<Array<Dynamic>->Dynamic>
{
private var headers : Array<String>;
private var contents : Array<String>;
public function new(aHeaders : Array<String>, aContents : Array<String>) {
headers = aHeaders;
contents = aContents;
}

function __resolve( name : String ) : Array<Dynamic>->Dynamic {
var index = getHeaderPosition(name);
var contents = this.contents;
if(index != -1) {
return function(args:Array<Dynamic> ):Dynamic {
return contents[index];
};
} else {
return null;
}
}
...
}


The implementation of the CsvFile (without the file load part):


class CsvFile {
var fileName : String;
var contents : List<Array<String>>;
var headers : Array<String>;

public function new(aFileName:String) {
...
}

public function entries() : List<CsvFileEntry> {
var headers = this.headers;
return contents.map(
function(data:Array<String>) :CsvFileEntry {
return new CsvFileEntry(headers,data);} );
}
}


A use of these classes is the following:


...
var f:CsvFile = new CsvFile("testfile.csv");
var cars:CsvFile = new CsvFile("cars.csv");


for (e in f.entries()) {
var v:String = e.Name([]);

neko.Lib.print(v);
neko.Lib.print("<br/>");
}
for (c in cars.entries()) {
var v:String = c.Model([]);
neko.Lib.print(v);
neko.Lib.print("<br/>");
}
...


ActionScript

ActionScript 3 provides this functionality by using inheriting from the Proxy class. An excellent description of this mecanism can be found in method_missing in ActionScript 3/Flex.

The implementation of the CsvFileEntry is the following:


dynamic public class CsvFileEntry extends Proxy
{

private var headers: Dictionary;
private var contents: Array;
public function CsvFileEntry(headers : Dictionary, contents : Array )
{
this.headers = headers;
this.contents = contents;
}

flash_proxy override function callProperty(method: *, ...args): * {
if (headers[method] == null)
{
throw( new Error("Method not found: "+method.toString()));
}
else
{
var i:int = headers[method];
return contents[i];
}
}
}
}


The CsvFile class without the file loading code:


public class CsvFile
{
private var file : File;
private var contents : ArrayCollection;
private var headers: Dictionary;
public function CsvFile(file:File)
{
...
}
public function getEntries() : ArrayCollection
{
var result : ArrayCollection = new ArrayCollection();
for each (var entry:Array in contents) {
result.addItem(new CsvFileEntry(headers,entry));
}
return result;
}
}



A use of these classes:


var f:CsvFile = new CsvFile(new File("testfile.csv"));
var cars:CsvFile = new CsvFile(new File("cars.csv"));
for each( var e:CsvFileEntry in f.getEntries()) {
aList.addItem(e.Name());
}
for each( var c:CsvFileEntry in cars.getEntries()) {
aList.addItem(c.Year());
}


Perl


As commented in the previous post, Perl provides this functionality with the AUTOLOAD method. A nice description is provided here: AUTOLOAD: Proxy Methods


Implementation of the CsvFileEntry class is the following:


package CsvFileEntry;
use strict;
use Carp;
our $AUTOLOAD;


sub new {
my $self = {};
my $class = shift;

my %headers = %{$_[0]};
my @data = @{$_[1]};

$self->{Headers} = \%headers;
$self->{Data} = \@data;

my $al = scalar(@{$self->{Data}});

bless($self,$class);
return $self;
}

sub getfield {
my $self = shift;
my $key = shift;
my %headers = %{$self->{Headers}};
my @data = @{$self->{Data}};
return $data[$headers{$key}];
}

sub AUTOLOAD {
my $self = shift;
my $name = $AUTOLOAD;
$name =~ s/CsvFileEntry:://;

my %headers = %{$self->{Headers}};

unless (exists $headers{$name}) {
croak "Cannot access member $name";
}

my $key = $headers{$name};
my @data = @{$self->{Data}};

return $data[$key];
}

1;


Implementation of the CsvFile class is the following:


package CsvFile;
use strict;
use CsvFileEntry;

sub new {
...
}
...
sub content {
my $self = shift;
my @entries = map {CsvFileEntry->new($self->{Headers},\@{$_})} @{$self->{Content}};
return @entries;
}
1;



A use of this code is the following:


use CsvFile;

$f = CsvFile->new("testfile.csv");
$cars = CsvFile->new("cars.csv");

foreach $person ($f->content) {
my $name= $person->Name;
my $age = $person->Age;
print "$name $age \n";
}
foreach $car ($cars->content) {
my $model= $car->Model;
print "$model\n";
}




Languages not covered.

Some languages were not covered in these posts. For example in the previous post schlenk commented that Tcl provides this functionality with the unknown proc.

Also EcmaScript 4 seems to provide this functionality, in slide 14 of Tamarin and ECMAScript 4.

I hope I can cover more on these languages in the future.

Code for this post can be found here.

Monday, February 4, 2008

Handling a call to a missing method in different languages, Part 1

This is the first of a two-part series of posts about the way different languages allow you to handle a call to method that doesn't exist. I'll try to implement a little example with each of these languages. For this part I'm going to show Ruby, Smalltalk, Groovy and Boo.

The doesNotUnderstand message


Although this feature is called by many names, the origin may be the doesNotUnderstand message of Smalltalk. From its Wikipedia entry:


When an object is sent a message that it does not implement, the virtual machine sends the object the doesNotUnderstand: message with a reification of the message as an argument. The message (another object, an instance of Message) contains the selector of the message and an Array of its arguments...


This mecanism could be used for many tasks, from debugging to creating proxies. A nice reflection on this is The Best of method_missing and also in the reflection section of Smalltalk Wikipedia entry.

One of the most interesting uses is in the implementation of Ruby on Rails's ActiveRecord. In Under the hood: ActiveRecord::Base.find there's a nice description on how the find_... method is implemented using method_missing.


The example


For these posts I'm going to implement a little example of two classes that provides access to a CSV file by using this mecanism. For example given that we have the following file called "cars.csv" (taken from here):


Year,Make,Model
1997,Ford,E350
2000,Mercury,Cougar


and another called "scores.csv"


Name,Age,Score
Luis,31,1.8
John,35,1.9
Paul,25,1.6


For simplicity we assume that not double quotes are used.

Given that the first row are the headers, we can use this class to have access to the data of each record using the name of the header as if it was a member of the class. For example:


cs = CsvFile.new("cars.csv")
ps = CsvFile.new("scores.csv")

cs.each do|c|
puts c.Model
end

ps.each do|p|
puts p.Name
end


The basic strategy to create the example is to create two classes CsvFile and CsvFileEntry. One to represent the file and the other to represent each entry.

In general, the contents of the file will be loaded as an list of lists. The headers will be loading in a dictionary associated with its position.


The languages


For these posts I tried to find programming languages that have direct support for this feature. For most of these programming languages, the presented snippet is my first program in it, so please let me know if I missed something.

Ruby

In Ruby the method_missing method provides this functionality.

The method signature is the following:


obj.method_missing( aSymbol [, *args ] ) -> anObject


In our little example the:


class CsvFileEntry
def initialize(headers,content)
@headers = headers
@content = content
end
def method_missing(method_name,*args)
if (@headers.has_key? method_name.to_s) then
return @content[@headers[method_name.to_s]]
else
raise "Method not found #{method_name}"
end
end
end


Implementation for the CsvFile class is the following(without the file loading code):


class CsvFile
attr_reader :headers
attr_reader :content
def initialize(filename)
@filename = filename
@headers = Hash.new
@content = []
...
end

def entries
return content.collect {|c| CsvFileEntry.new(@headers,c)}
end
end


In the implementation of method_missing, the method_name argument is converted to string and used to lookup the name of the requested field. The headers instance variable contains a Hash with the positions of each header and the contents variable contains the contents of the entry.

Now we can use these classes as follows:


f = CsvFile.new("testfile.csv")
cars = CsvFile.new("cars.csv")

f.entries.each { |e| puts "#{e.Name} #{e.Age}" }

f.entries.each do |e|
puts e.Name
end

print "-------\n"

cars.entries.each do |c|
puts c.Model
puts c.Year
end


Smalltalk

As described above, in Smalltalk we have to implement the doesNotUnderstand method. This method receives a an instance of the Message class . This class contains information about the requested method and arguments.

The implementation of the CsvFileEntry class looks like this:


Object subclass: #CsvFileEntry
instanceVariableNames: 'headers contents'
classVariableNames: ''
poolDictionaries: ''
category: 'Langexplr-Classes'!


doesNotUnderstand: aMessage
| index |
^(headers includesKey: aMessage selector)
ifTrue:
[index := headers at: (aMessage selector).
contents at: index.]
ifFalse: [super doesNotUnderstand: aMessage].



initializeWith: theContents headers: theHeaders
headers := theHeaders.
contents := theContents.
^self.


The implementation of the CsvFile class(without the file loading code) looks like this:


Object subclass: #CsvFile
instanceVariableNames: 'fileName contents headers'
classVariableNames: ''
poolDictionaries: ''
category: 'Langexplr-Classes'


getContents
^contents.


getEntries
^(contents collect:[:e | (CsvFileEntry new) initializeWith: e headers: headers ]).

initializeWithFileName: aFileName
...
^ self.


An example of a use of these classes is the following:


scores := CsvFile new initializeWithFileName: 'testfile.csv'.

cars := CsvFile new initializeWithFileName: 'cars.csv'.

cars getEntries do:
[:entry|
Transcript show: (entry Model)].

scores getEntries do:
[:entry|
Transcript show: (entry Name)] .


Groovy

Groovy provides this feature for methods and properties. A description of this mecanism can be found in Using methodMissing and propertyMissing
. A nice example of a use of this mecanism is the GORM's Domain Class Querying.

In Groovy we need to implement the def propertyMissing(String name) method or the def methodMissing(String name,args) to handle a property or method access. The following CsvFileEntry implementation uses overrides both methods to provide property access and getter method(getXXXXX) access.


public class CsvFileEntry {
private HashMap headers;
private String[] contents;

CsvFileEntry(HashMap headers,String[] contents) {
this.headers = headers;
this.contents = contents;
}
def propertyMissing(String name) {
if (headers[name] != null) {
return this.contents[this.headers[name]];
} else {
throw new RuntimeException("Property not found ${name}");
}
}
def methodMissing(String name,args) {
def getterNameResult = name =~ /get(.*$)/;
if (getterNameResult.matches() &&
headers[getterNameResult.group(1)] != null) {
return this.contents[this.headers[getterNameResult.group(1)]];
} else {
throw new RuntimeException("Method not found ${name}");
}
}
}


The implementation for the CsvFile class is the following(without the file loading part):


span class="srckeyw">public class CsvFile {
def HashMap headers;
def contents;

CsvFile(String fileName) {
...
}

def entries() {
def result = []
for ( c in contents) {
result.add(new CsvFileEntry(headers,c));
}
return result
}
}


A use of this code looks like this:


def scores = new CsvFile("testfile.csv")
def cars = new CsvFile("cars.csv")


for ( e in scores.entries() ) {
println("${e.Name} --> ${e.getAge()}")
}

for ( c in cars.entries()) {
println(c.getModel());
println(c.Year)
}


Boo

In Boo this functionality is available by implementing the IQuackFu interface. A nice explanation of this feature is available from: If it walks like a duck and it quacks like a duck . Also Dynamic Inheritance - fun with IQuackFu provides more information . A very nice example called XmlObject.boo (available from Boo source distribution) shows how IQuackFu is used to easy the access to Xml trees.

The IQuackFu interface contains the following members:

  • def QuackInvoke(name as string, args as (object)) as object: for method calls

  • def QuackGet(name as string) as object: for property access

  • def QuackSet(name as string, value) as object: for property assignment




Since Boo allowed handling both method and property access I created two ways to access the data: by using the name of the header as a property or a call to a method called GetXXXXX.

The CsvFileEntry implementation is the following:


class CsvEntry(IQuackFu):
content as (string)
headers as Hash
public virtual def constructor(aContent as (string),aHeaders as Hash):
content = aContent
headers = aHeaders

def QuackInvoke(name as string, args as (object)) as object:
r = /Get(?<name>.*$)/.Match(name)

if (r.Success and headers.ContainsKey(r.Groups["name"].Value)):
index = headers[r.Groups["name"].Value]
return content[index]
else:
raise InvalidOperationException("Method ${name} not found")


def QuackSet(name as string, value) as object:
pass

def QuackGet(name as string) as object:
if(headers.ContainsKey(name)):
index = headers[name]
return content[index]
else:
raise InvalidOperationException("Property ${name} not found")


The CsvFile implementation (without the file loading part) :


class CsvFile():
headers = {}
content = []
public virtual def constructor(fileName as string):
...

public def Entries():
for e as (string) in content:
yield CsvEntry(e,headers)



A use of this class:


csvF = CsvFile("testfile.csv")
cars = CsvFile("cars.csv")


for e in csvF.Entries():
print e.Name


for c in cars.Entries():
print c.GetModel()



Code for this post can be found here.

For the next post the Python, Objective-C, Haxe, ActionScript and Perl examples will be presented.