Showing posts with label boo. Show all posts
Showing posts with label boo. Show all posts

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.

Wednesday, June 20, 2007

Calling the Boo compiler from a Boo program

In this post I'm going to show a little demo of creating a piece of a Boo program on the fly, compile it and execute it as part of the main program.

The Boo language implementation comes with two very useful and interesting libraries: Boo.Language.Parser.dll and Boo.Language.Compiler.dll. These libraries give the developer access to Boo's parser and compiler for use within any Boo(or .NET) program. Also the AST classes( Boo.Lang.Compiler.Ast) and visitors(Boo.Lang.Compiler.Ast.Visitors) are available to create and manipulate pieces of programs .

The ast-to-string.boo,ast-to-xml.boo,run-ast.boo and run-ast-without-compiler.boo examples included with the Boo distributions shows how to use both the AST and the compiler.

The little demo I worked on, is a program that shows the content of an AST tree using a Winforms TreeView control. In order create this little experiment I wanted to create a class that inherits from Boo.Lang.Compiler.Ast.DepthFirstVisitor that will create the TreeNode instances used to visualize the tree.

Creating a class that inherits from Boo.Lang.Compiler.Ast.DepthFirstVisitor is a tedious work since you have to create a method for each kind of AST node with the same body. Because of this the Ast classes and the compiler to create the class and compile it on the fly. Here's the code.


import System
import System.Reflection
import System.IO
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Parser
import System.Windows.Forms from System.Windows.Forms


// Get the type instance for DepthFirstVisitor
a = Assembly.Load("Boo.Lang.Compiler")
t = a.GetType("Boo.Lang.Compiler.Ast.DepthFirstVisitor")

// Create a class definition for a custom visitor
myVisitor = ClassDefinition(Name:"DynamicVisitor")
myVisitor.BaseTypes.Add(SimpleTypeReference("Boo.Lang.Compiler.Ast.DepthFirstVisitor"))

// Add a new field for our node stack
myVisitor.Members.Add(Field(Name:"stck",
Type:SimpleTypeReference("System.Collections.Stack"),
Modifiers:TypeMemberModifiers.Public))

// Create all 'Enter' methods
for m as MethodInfo in [m for m in t.GetMethods() if m.Name.StartsWith("Enter")]:
nm = Method(Name: m.Name, Modifiers: TypeMemberModifiers.Override,
Body:Block(),ReturnType:SimpleTypeReference("System.Boolean"))
nm.Parameters.Add(ParameterDeclaration(Name:"p",
Type:SimpleTypeReference(
Name:m.GetParameters()[0].ParameterType.FullName)))

// Node for TreeNode('')
tnCreation = MethodInvocationExpression(ReferenceExpression("TreeNode"))
tnCreation.Arguments.Add(
StringLiteralExpression(m.GetParameters()[0].ParameterType.Name))

// Create node for 't = TreeNode('')'
decl = DeclarationStatement(
Declaration: Declaration(Name:"t",
Type: SimpleTypeReference("System.Windows.Forms.TreeNode")),
Initializer: tnCreation)

nm.Body.Add(decl)

// Create nodes for '(stck.Peek() as TreeNode).Nodes.Add(t)'
at = MethodInvocationExpression(
MemberReferenceExpression(
Target:MemberReferenceExpression(
Target: TryCastExpression(
Target:MethodInvocationExpression(
MemberReferenceExpression(
Target:ReferenceExpression("stck"),
Name:"Peek")),
Type:SimpleTypeReference("System.Windows.Forms.TreeNode")),
Name:"Nodes"),
Name:"Add"))
at.Arguments.Add(ReferenceExpression("t"))

nm.Body.Add(ExpressionStatement(at))

// Create node for 'stck.Push(t)'
mie = ExpressionStatement(
MethodInvocationExpression(
MemberReferenceExpression(
Target:ReferenceExpression("stck"),Name:"Push")))

(mie.Expression as MethodInvocationExpression).Arguments.Add(ReferenceExpression("t"))

nm.Body.Add(mie)

// Add 'return true' statement
nm.Body.Add(ReturnStatement(Expression:BoolLiteralExpression(Value:true)))

myVisitor.Members.Add(nm)


// Create all 'Leave' methods
for m as MethodInfo in [m for m in t.GetMethods() if m.Name.StartsWith("Leave")]:
// Create 'stck.Pop()' node
mie = ExpressionStatement(
MethodInvocationExpression(
MemberReferenceExpression(
Target:ReferenceExpression("stck"),Name:"Pop")))
// CreateNode
nm = Method(Name: m.Name, Modifiers: TypeMemberModifiers.Override,
Body:Block())
nm.Body.Add(mie)
nm.Parameters.Add(ParameterDeclaration(Name:"p",
Type:SimpleTypeReference(
Name:m.GetParameters()[0].ParameterType.FullName)))

myVisitor.Members.Add(nm)

// Compile unit and module creation
cu = CompileUnit()
mod = Boo.Lang.Compiler.Ast.Module(Name:"Module")
cu.Modules.Add(mod)
mod.Imports.Add(Import(Namespace:"System.Windows.Forms"))
mod.Members.Add(myVisitor)

// Initialize compiler preferences
pipeline = Pipelines.CompileToMemory()
ctxt = CompilerContext(cu)

// Run the compiler
pipeline.Run(ctxt)

// Check the results
if (ctxt.GeneratedAssembly != null):
// Create an instance of the new visitor and initialize it
i as object = ctxt.GeneratedAssembly.CreateInstance("DynamicVisitor");
t = ctxt.GeneratedAssembly.GetType("DynamicVisitor")
tStack = System.Collections.Stack()
tStack.Push(System.Windows.Forms.TreeNode("root"))
t.GetField("stck").SetValue(i,tStack );
v as DepthFirstVisitor = i

// Parse a file an run the visitor
//tast = BooParser.ParseString("myUnit","x = w.foo(1)")
tast = BooParser.ParseFile(argv[0])
tast.Accept(i)

//Initialize a form an show the results
frm = Form(Text: "AST content",Width: 300,Height: 300)
tv = TreeView(Dock: DockStyle.Fill)
tv.Nodes.Add(tStack.Pop() as TreeNode)
frm.Controls.Add(tv)
Application.Run(frm)
else:
for e in ctxt.Errors:
print e




Here's a sample of the output.

Sunday, February 18, 2007

List comprehensions across languages

According to Wikipedia a list comprehension is a language construct that lets you specify the contents of a list based on the set builder notation which used in mathematics to describe the members of a set.

For example in order to describe "the set of all natural numbers greater than 4 and lower than 10" using this notation we say:



A list comprehension expression is composed of the following elements:



Where:
  • set member describes each element of the set. .
  • generator generate values to be included in the set. More than one generator can be used. In the case, all possible combinations are tested.
  • filter expressions filter generated values.
In this post I'm going to show examples written in several languages that have a construct similar to list comprehensions. Three examples are used:

1. Get all even numbers from a list

A simple example that filters the contents of a list of integers to get all the even numbers.

2. Get all the files that are greater than some given size

An example to show how list comprehensions can be used to work on elements other than numbers.

3. Solve the 4(ABCD) = DCBA puzzle

An example to show the use of several generators. This puzzle consists in finding the values of digits A,B,C,D given that ABCD*4 = DCBA where ABCD and DCBA are 4-digit numbers.


And now the code...


Haskell

The syntax of list comprehensions in Haskell can be considered syntactic sugar for the List Monad.

Syntax is described here.

Example 1:


getEvenNumbers aList =
[ x | x >- aList, x `mod` 2 = 0]


Example 2:


import Directory
import Monad
import IO

...

getFilesGreaterThan size directory =
do
contents <- getDirectoryContents directory
files <- filterM doesFileExist $ map ((++) directory) contents
filesWithSize <- mapM fsize files
return [fname | (fname,fsize) <- filesWithSize, fsize >= size]
where
fsize f =
do {fd <- openFile f ReadMode;
size <- hFileSize fd;
hClose fd;
return (f,size)}



Example 3:


solveABCDProblem =
[ (a,b,c,d) |
a <-[0..9],
b <-[0..9],
c <-[0..9],
d <-[0..9],
a /= 0,
(1000*a + 100*b + 10*c + d)*4 ==
(1000*d + 100*c + 10*b + a)]


F#

F# sequence comprehensions syntax is described here . One nice feature of F# sequence comprehensions is that not only lists can be used in generators, but any object implementing IEnumerable . Also the result of a sequence comprehension an IEnumerable.

Example 1:


let GetEvenNumbers (l) =
{ for i in l
when i % 2 = 0 -> i }


Example 2:


let GetFilesGreaterThan( size ,directory) =
let dInfo = (new System.IO.DirectoryInfo(directory))
in { for f in dInfo.GetFiles()
when (f.Length >= size) -> f }


Example 3:


let SolveProblem() =
{ for a in 0 .. 9
for b in 0 .. 9
for c in 0 .. 9
for d in 0 .. 9
when (1000*a + 100*b + 10*c + d)*4 =
(1000*d + 100*c + 10*b + a) -> (a,b,c,d) }



Scala

Scala has the concept of sequence comprehensions which works with several kinds of collections.

Example 1:

def getEvenNumbers(l : List[int]) =
for { val i <- l
i % 2 == 0 }
yield i

Example 2:

def getFilesGreaterThan(size : int, folder : String) = {
val folderD = new java.io.File(folder)
for{ val f <- folderD.listFiles()
f.isFile()
f.length() >= size
} yield f.getName()
}

Example 3:

def solveProblem() =
for {
val a <- List.range(0,9)
val b <- List.range(0,9)
val c <- List.range(0,9)
val d <- List.range(0,9)
a != 0
(a*1000 + b*100 + c*10 + d)*4 == (d*1000 + c*100 + b*10 + a)
} yield List(a,b,c,d)



Erlang

Erlang's list comprehensions are described here .


Example 1:

get_even_numbers(L) -> [X || X <- L, (X rem 2) == 0].

Example 2:

get_files_greater_than(Size,Directory) ->
[Fn || Fn <- filelib:wildcard(lists:append(Directory,"*")),
not filelib:is_dir(Fn),
filelib:file_size(Fn) > Size].

Example 3:

solve_problem() ->
[{A,B,C,D} ||
A <- [0,1,2,3,4,5,6,7,8,9],
B <- [0,1,2,3,4,5,6,7,8,9],
C <- [0,1,2,3,4,5,6,7,8,9],
D <- [0,1,2,3,4,5,6,7,8,9],
A /= 0,
(1000*A + 100*B + 10*C + D)*4 == (1000*D + 100*C + 10*B + A) ].




Python

Python list comprehension syntax is described here.

Example 1:

def getEvenNumbers(l):
return [x for x in l if x % 2 == 0]

Example 2:

def listFilesGreaterThan(size,directory):
return [fileName
for fileName in os.listdir(directory)
if os.path.isfile(os.path.join(directory,fileName))
if os.path.getsize(os.path.join(directory,fileName)) > size]

Example 3:

def solveProblem():
return [ (a,b,c,d)
for a in range(0,9)
for b in range(0,9)
for c in range(0,9)
for d in range(0,9)
if a != 0
if ((a*1000 + b*100 + c*10 + d)*4) ==
(d*1000 + c*100 + b*10 + a)]



Nemerle

Nemerle list comprehensions are described here.

Example 1:

public GetEvenNumbers(l : list[int]) : list[int] {
$[x | x in l, x % 2 == 0]
}

Example 2:

public GetFilesGreaterThan(size : int, directory: string) : list[string] {
def dInfo = DirectoryInfo(directory);
$[f.Name | f in dInfo.GetFiles(), f.Length >= size]
}

Example 3:

public SolveProblem() : list[int*int*int*int]{
$[(a,b,c,d) |
a in [0..9],
b in [0..9],
c in [0..9],
d in [0..9],
a != 0,
(1000*a + 100*b + 10*c + d)*4 == (1000*d + 100*c + 10*b + a) ]
}



Boo

Because of its influence in the language, list generators in Boo are very similar to list comprehensions in Python.

Example 1:

def getEvenNumbers(l):
return [x for x as int in l if x % 2 == 0]

Example 2:

def getFilesGreaterThan(size as int,directory as string):
dInfo = DirectoryInfo(directory)
return [f.Name for f in dInfo.GetFiles() if f.Length > size]

Example 3:

def solveProblem():
return [(a,b,c,d)
for a in range(0,9)
for b in range(0,9)
for c in range(0,9)
for d in range(0,9)
if a != 0 and ((1000*a + 100*b + 10*c + d)*4) == (1000*d + 100*c + 10*b + a)]


Visual Basic 9 (LINQ)

The LINQ feature of VB 9 allows the creation of expressions similar to list comprehesions. A nice feature of LINQ is that it operates with any object that implements IEnumerable<T> and also returns an IEnumerable<T> .

Example 1:

Public Shared Function GetEvenNumbers(ByVal l as List(Of Integer)) as List(Of Integer)
Return New List(Of Integer) ( _
From x in l _
Where (x Mod 2) = 0 _
Select x )
End Function

Example 2:

Public Shared Function GetFilesGreaterThan(ByVal size As Integer,directory As String) As List(Of FileInfo)
Dim dirInfo = new DirectoryInfo(directory)

return new List(Of FileInfo) (From f in dirInfo.GetFiles() _
Where f.Length >= size _
Select f)
End Function:


Example 3:

Public Shared Sub SolveProblem()
Dim results = _
From a in Range(0,9), _
b in Range(0,9), _
c in Range(0,9), _
d in Range(0,9) _
Where (1000*a + 100*b + 10*c + d)*4 = _
(1000*d + 100*c + 10*b + a) AndAlso _
a <> 0 _
Select New { A := a,B := b,C := c,D := d }
For Each result in results
Console.WriteLine("A={0} B={1} C={2} D={3}",result.A,result.B,result.C,result.D)
Next

End Sub


Public Shared Function Range(i as Integer,n as Integer) as List(Of Integer)
Dim result as new List(Of Integer)()
For i = i To n
result.Add(i)
Next
Return result
End Function


C# 3.0 (LINQ)

As with VB, the LINQ feature of C# 3.0 allows the creation of expressions similar to list comprehesions.

Example 1:

static List<int> GetEvenNumbers(List<int> l)
{
return new List<int>( from x in l
where x % 2 == 0
select x);
}

Example 2:

static List<FileInfo> GetFilesGreaterThan(int size,string directory)
{
DirectoryInfo dirInfo = new DirectoryInfo(directory);

return new List (
from f in dirInfo.GetFiles()
where f.Length >= size
select f
);
}



Example 3:

static void SolveProblem()
{
var results =
from a in range(0,9)
from b in range(0,9)
from c in range(0,9)
from d in range(0,9)
where (1000*a + 100*b + 10*c + d)*4 ==
(1000*d + 100*c + 10*b + a) &&
a != 0
select new {
A=a,B=b,C=c,D=d
};


foreach(var result in results) {
Console.WriteLine("A={0} B={1} C={2} D={3}",
result.A,result.B,result.C,result.D);
}
}

static IEnumerable<int> range(int s,int n)
{
for(int i = s ;i <= n;i++) {
yield return i;
}
}




Powershell

Although not explicitly having a list comprehension feature, it's interesting to use Powershell pipeline to get a similar funcionality.

Example 1:

Function GetEvenNumbers($l) {
$l | ? {$_ % 2 -eq 0}
}

Example 2:

function GetFilesGreaterThan($size, $folder) {
get-childitem $folder | ? { $_.Length -gt $size}
}

Example 3:

Function SolveProblem() {
(0..9) | % { $a=$_ ;(0..9) |
% {$b = $_ ; (0..9) |
% {$c = $_ ; (0..9) |
% {$d = $_ ; @{a=$a;b=$b;c=$c;d=$d}} } } } |
? { ((1000*$_.a + 100*$_.b + 10*$_.c + $_.d )*4) -eq
(1000*$_.d + 100*$_.c + 10*$_.b + $_.a )} |
% { write-host $_.a $_.b $_.c $_.d}
}


Others

Some other languages with list comprehensions where not covered by this post. Among this languages is Fortress(waiting for reference implementation to support this) and Perl 6 . Future posts will cover this languages.