views:

534

answers:

3

Hi,

There is a question regarding usage of functional programming techiques in C# code. Example

Let we have interface

interface IGraph { /*contains vertices and edges*/}

Suppose we need to layout graph's vertices (assign Point to each vertex).

interface ILayoutInfo {
  Point GetVertexPoint(vertex);
}

Simple layout route can have such signature:

ILayoutInfo SimpleLayout(IGraph graph);

Which can be used in such way

void Demo() {
  IGraph graph = CreateGraphInAnyWay();
  ILayoutInfo layout = SimpleLayout(graph);
  PrintCoordinates(graph,layout);
}

In design below PrintCoordinates need both references to graph and layout.

Consider functional style design where layouting routing augments graph information with information about graph vertices coordenates.

ILayoutedGraph SimpleLayoutNew(IGraph graph);

Where ILayoutedGraph implements BOTH IGraph and ILayoutInfo

void DemoNew() {
  IGraph graph = CreateGraphInAnyWay();
  ILayoutedGraph layoutedGraph = SimpleLayoutNew(graph);
  PrintCoordinatesNew(layoutedGraph);
}

1)In this design PrintCoordinatesNew gets only ONE parameter. 2)Weird interface ILayoutedGraph was born which doesn't contain any methods and just wraps other interfaces. If some library has other types like INetwork, ITree we end up creating wrap interfaces ILayoutedNetwork, ILayoutedTree (which is bad).

So such techique is used only in functinal languages just because they can't work in other way (there are no state so function must combine input with calculated info to be used by outer routines) or it is viable in imperative world too?

Thanks a lot,

PS: a more verbose pretty printed example can be found here http://tivadj.blogspot.com/2009/02/designing-c-api-in-functional-style.html

A: 

Can you implement this using a class that implements both interfaces and casting the returns as that class?

ck
The problem is what API (interfaces) to publish:traitional stylecase1) IGraph, ILayoutInfo and SimpleLayout(IGraph):ILayoutInfoor functional stylecase2) IGraph, ILayoutedGraph SimpleLayoutNew(IGraph):ILayoutedGraph====ILayoutedGraph really can be implemented by some internal class.
tivadj
A: 

There is no problem with your original API of

void Demo() {
  IGraph graph = CreateGraphInAnyWay();
  ILayoutInfo layout = SimpleLayout(graph);
  PrintCoordinates(graph,layout);
}

It is perfectly functional. An imperative API would involve a change to graph once it is created. Eg

void Demo() {
  IGraph graph = CreateGraphInAnyWay();
  graph.Layout(new SimpleLayout()); // changes the state of graph
  PrintCoordinates(graph);
}

As for the problem of ILayoutedGraph, ILayoutedTree, ILayoutedQueue, etc, I think you would get around this by generic classes in a functional languages and multiple inheritance in the OO languages where this is allowed.

Personally, I would recommend generics: ILayout<a> where a is something with edges that needs to be laid out.

Nathan Sanders
A: 

If seems that what disturbs you when passing two arguments is that your layout (ILayoutInfo) is linked to the graph used to generate it. I would be meaningless to pass a layout with a graph that was not used to generate it.

In this case, you can keep a reference to the graph in the layout info, and provide an accessor on the ILayoutInfo interface.

This way, you can only pass the ILayoutInfo instance, and you PrintCoordinates function can still acces the graph that was used to generate the ILayoutInfo.

If you have other kind of object that can generate layout infos, use a common interface for them, or make the ILayoutInfo generic.

Think Before Coding
Thanks. You really give me a breath of fresh air.
tivadj