Archive
Duck typing in C++, F# and C#
C++ templates are very powerful and differs in many ways from generics in C#. One of the things I like about C++ templates is that they allow a kind of statically checked duck typing as examplified below:
struct Customer
{
int Id; string Name; string Address;
void Print() const { cout << "id=" << Id << ", name=" << Name << ", address=" << Address << endl; }
};
struct Product
{
int Id; string Name; int Price;
void Print() const { cout << "id=" << Id << ", name=" << Name << ", price=" << Price << endl; }
};
template<class T> int getId(const T& t) { return t.Id; }
template<class T> void print(const T& t) { t.Print(); }
void _tmain(int argc, _TCHAR* argv[])
{
Customer customerSample; customerSample.Id = 66; customerSample.Name = "Egon"; customerSample.Address = "Some street";
Product productSample; productSample.Id = 24; productSample.Name = "Candy"; productSample.Price = 284;
cout << "Id of customer sample is " << getId(customerSample) << endl;
cout << "Id of product sample is " << getId(productSample) << endl;
print(customerSample);
print(productSample);
}
The getId and print methods are duck typed in the sense that any class having an Id property, or a Print method respectivly, can be used as an argument. The requirements are statically checked by the compiler which means that if a class is missing the Id property or the print method the program will not compile.
I was happy to discover that F# allows a very similiar solution:
type Customer(id : int, name : string, address : string) =
member this.Id = id
member this.Name = name
member this.Address = address
member this.Print() = printf "id=%A, name=%A, address=%A\n" id name address
type Product(id : int, name : string, price : int) =
member this.Id = id
member this.Name = name
member this.Price = price
member this.Print() = printf "id=%A, name=%A, price=%A\n" id name price
let inline getId arg = ( ^a : (member Id : int) arg )
let inline print arg = ( ^a : (member Print : unit -> unit) arg )
let customerSample = Customer(66, "Egon", "Some street 132")
let productSample = Product(24, "Candy", 284)
getId customerSample |> printf "Id of customer sample is %A\n"
getId productSample |> printf "Id of product sample is %A\n"
print customerSample
print productSample
I will not dig into the details but the getId and print functions are more or less equivalent to their C++ counterparts. Matthew Podwysocki provides more information in his blog.
In C# 4 we can use dynamic to achieve this kind of duck typing
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public void Print() { Console.WriteLine("id={0}, name={1}, address={2}", Id, Name, Address); }
}
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
public void Print() { Console.WriteLine("id={0}, name={1}, price={2}", Id, Name, Price); }
}
class Program
{
static int GetId(dynamic t)
{
return t.Id;
}
static void Print(dynamic t)
{
t.Print();
}
static void Main(string[] args)
{
var customerSample = new Customer { Id = 66, Name = "Egon", Address = "Some street" };
var productSample = new Product { Id = 24, Name = "Candy", Price = 284 };
Console.WriteLine("Id of customer sample is {0}", GetId(customerSample));
Console.WriteLine("Id of product sample is {0}", GetId(productSample));
Print(customerSample);
Print(productSample);
}
}
However, this code is not statically checked by the compiler. Instead the check for the Id property and the Print method is done at runtime. Having the check done at runtime ofcourse makes the code much more fragile.
List permutations in F#
let (++) a b = List.append a b
let cons x xs = x::xs
let rec permute (xss : ‘a list) : ‘a list list =
let permuteFirst (ls : ‘a list) : ‘a list list =
let rec f yss xss =
match xss with
| [] -> []
| x::xs -> (x::yss++xs) :: (f (yss ++ [x]) xs)
f [] ls
let permuteRest (lss : ‘a list) : ‘a list list =
match lss with
| [] -> raise (new System.Exception());
| (l::ls) -> List.map (cons l) (permute ls)
match xss with
| [] -> []
| [x] -> [[x]]
| x::xs -> permuteFirst xss |> List.map permuteRest |> List.concat
permute [1;2;3] gives [[1; 2; 3]; [1; 3; 2]; [2; 1; 3]; [2; 3; 1]; [3; 1; 2]; [3; 2; 1]].