On 07/11/2012 02:00 PM, David Piepgrass wrote:

I am particularly a fan of structural typing. I don't know if Rust uses
it but Opa and other functional languages often do. You see, there's a
problem that pops up in .NET all the time, and probably the same problem
exists in D.

Any time two libraries want to use the same concept, but the concept is
not in the standard library, they need to define it. For instance if
there is no "Point" type in the standard library, but two unrelated
libraries need points, they will both define their own (amazingly,
Points are poorly thought out in .NET and tightly bound to GUI
libraries, so people define their own in some cases):

// JoesLibrary
struct Point!T { T x, y; /* followed by some manipulation functions */ }

// FunkyLibrary
struct Point!T { T x, y; /* followed by other manipulation functions */ }

Sadly, the two point types are not compatible with each other. A client
that wants to use both libraries now has an interoperability problem
when he wants to pass data between the.

Even a client that uses only one of the library, let's call it
"JoesLibrary" has to import Point from "JoesLibrary", even if its
functionality is not quite what the client wants. It would be much nicer
if the client could define his own Point struct that seamlessly
interoperates with Joes'. In D this is currently impractical, but I
would enjoy designing a way to make it work (before you point out that
"what if x and y are in a different order in the two structs" and "it
could be T X,Y in one and T x,y in the other", yes, I know, It's on my
list of problems to cleverly solve)

A similar problem exists with interfaces, where two unrelated libraries
expose two similar classes with some common functions, but you can't
cast them to a common type in D. This is a solved problem in Go
(http://www.airs.com/blog/archives/277) and it's actually pretty easy
for a compiler to magically cast a class to an interface that the class
did not declare--if the underlying language is designed for that, anyway.

In fact, in .NET at least, the same problem exists even if the libraries
DO know about each other and are even written by the same person and use
identical interfaces. The problem is, if I write two libraries A and B,
and I want them to be interoperable, then I need to factor out the
common structs and interfaces to a microscopic third library, I. But
from the client's perspective, if a client only knows about A or B, he
will think it's stupid that I require him to use and deploy two
DLLs/so's (A and I, or B and I) instead of one. In D I guess it's not
the same, though.


I'm pretty sure this interoperability thing is solved in D, at least at compile time.

Example:

import std.traits;

/// Returns true if T is a Point type.
template isPoint(T)
{
    enum bool isPoint = is(typeof(
    {
        T point;

        // (x,y) should be numeric.
        static assert ( isNumeric!(typeof(point.x)) );
        static assert ( isNumeric!(typeof(point.y)) );

        auto x = point.x; // x is readable
        point.x = x;      // x is writable

        auto y = point.y; // y is readable
        point.y = y;      // y is writable
    }));
}

struct MyPointType
{
    float x;
    float y;
}

struct AnotherPointType
{
    int x;
    int y;
}

struct NotAPoint
{
    char[] x;
    char[] y;
}

// TODO: are x and y allowed to have differing types?
static assert(isPoint!MyPointType);
static assert(isPoint!AnotherPointType);
static assert(!isPoint!NotAPoint);

auto myPointCalculation(P1,P2)( P1 p1, P2 p2 ) if ( isPoint!P1 && isPoint!P2 )
{
    p1.x += p2.x;
    p1.y += p2.y;
    return p1;
}

import std.stdio;
void main()
{
    MyPointType p1;
    AnotherPointType p2;
    p1.x = 3.5;
    p1.y = 5.0;
    p2.x = 2;
    p2.y = 2;
    writefln("(before) p1 == (%s, %s)",p1.x,p1.y);
    p1 = myPointCalculation(p1,p2);
    writefln("(after)  p1 == (%s, %s)",p1.x,p1.y);
}



At the command line:
chad@Hugin ~/dprojects/dtesting/points $ dmd points.d
chad@Hugin ~/dprojects/dtesting/points $ ./points
(before) p1 == (3.5, 5)
(after)  p1 == (5.5, 7)

Reply via email to