Jump to page: 1 2
Thread overview
Like getClass()
Sep 27, 2008
bearophile
Sep 27, 2008
Sergey Gromov
Sep 27, 2008
bearophile
Sep 27, 2008
torhu
Sep 27, 2008
bearophile
Sep 27, 2008
bearophile
Sep 27, 2008
Sergey Gromov
Sep 27, 2008
Christopher Wright
Sep 28, 2008
Sergey Gromov
Sep 28, 2008
bearophile
Sep 28, 2008
Denis Koroskin
Sep 28, 2008
Sergey Gromov
Oct 03, 2008
Sergey Gromov
Oct 17, 2008
Tim M
September 27, 2008
I'm trying to learn more about D object system (this is derived from a discussion I've had in #D), I have problems fully understanding some of the things the D docs say. This is a little Java program for reference:

// Java code
import java.util.*;
interface FooBar {}
class Foo implements FooBar {}
class Bar implements FooBar {}
public class test {
    public static void main(String[] args) {
        ArrayList<FooBar> things = new ArrayList<FooBar>();
        things.add(new Bar());
        things.add(new Foo());
        for (FooBar thing : things)
            System.out.println(thing.getClass());
    }
}
/*
Output of the Java version:
class Bar
class Foo
*/


I have tried to translate it to D, and I have failed so far, this code compiles and runs, but I'd like to see the original class names in the output:

// D code
import std.stdio;
interface FooBar {}
class Foo : FooBar {}
class Bar : FooBar {}
void main() {
    FooBar[] things;
    things ~= new Bar;
    things ~= new Foo;
    foreach (thing; things)
        writefln(typeid(typeof(thing)));
}
/*
Output of the D version:
test.FooBar
test.FooBar
*/

As you can see in D I am not able yet to find the class of the objects inserted into the 'things' array. Do you have suggestions? (I'd like to do this to sort the 'things' array according to the class).

Bye and thank you,
bearophile
September 27, 2008
Sat, 27 Sep 2008 12:15:07 -0400,
bearophile wrote:
> // D code
> import std.stdio;
> interface FooBar {}
> class Foo : FooBar {}
> class Bar : FooBar {}
> void main() {
>     FooBar[] things;
>     things ~= new Bar;
>     things ~= new Foo;
>     foreach (thing; things)
>         writefln(typeid(typeof(thing)));
> }
> /*
> Output of the D version:
> test.FooBar
> test.FooBar
> */

typeof() gives a static type of an object.  But I was sure that thing.classinfo.name should have referred to the dynamic type name. Apparently it's not the case, it prints the same test.FooBar as in your test.
September 27, 2008
Sergey Gromov:
> typeof() gives a static type of an object.  But I was sure that thing.classinfo.name should have referred to the dynamic type name. Apparently it's not the case, it prints the same test.FooBar as in your test.

Thank you for your answer.
So the question here is: is the information I need present at runtime somewhere?
If the answer is true, then the problem is how to get it.

I think this page of the docs may be improved with few graphical drawings of the data structures it talks about (with lines that show where the pointers point to at runtime in a simple example); such images can probably give all or most of the answers I was looking for:
http://www.digitalmars.com/d/1.0/phobos/object.html

Bye,
bearophile
September 27, 2008
bearophile wrote:
> Sergey Gromov:
>> typeof() gives a static type of an object.  But I was sure that thing.classinfo.name should have referred to the dynamic type name.  Apparently it's not the case, it prints the same test.FooBar as in your test.
> 
> Thank you for your answer.
> So the question here is: is the information I need present at runtime somewhere?
> If the answer is true, then the problem is how to get it.

obj.classinfo doesn't work the way you'd expect with an interface, but it works when you've got an object:

writefln((cast(Object)thing).classinfo.name);

This does look ugly, though.
September 27, 2008
torhu:
> writefln((cast(Object)thing).classinfo.name);

It works, thank you very much. Now I'll try to use it for the original purposes...... I'll have to work some more. I'll show here the results if I finish.


> This does look ugly, though.

Well, better ugly than not having any way to solve the problem :-)

Bye,
bearophile
September 27, 2008
I have solved my original problem :-) I show here the code for reference:

This is the original Python code, that sorts a python list (array) of objects according to their class:


class Circle:
    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
    def draw(self):
        print "Drawing Circle at (%s,%s) with radius %s" % (self.x, self.y, self.radius)

class Square:
    def __init__(self, x, y, width):
        self.x = x
        self.y = y
        self.width = width
    def draw(self):
        print "Drawing Square at (%s,%s) with width %s" % (self.x, self.y, self.width)

if __name__ == "__main__":
    order = [Circle, Square] # the order in which to draw the shapes
    shapes = [Circle(1,1,5), Square(2,4,3), Circle(3,3,7), Square(4,2,4)]
    shapes.sort(key=lambda s: order.index(s.__class__))
    for shape in shapes:
        shape.draw()




This is my best D translation so far, I am happy enough:

import std.stdio: writefln;
import d.func: sort, findPos;

interface Shape {
    void draw();
}

class Circle : Shape {
    float x, y, radius;
    this(float x, float y, float radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }
    void draw() {
        writefln("Drawing Circle at (%s,%s) with radius %s", x, y, radius);
    }
}

class Square : Shape {
    float x, y, width;
    this(float x, float y, float width) {
        this.x = x;
        this.y = y;
        this.width = width;
    }
    void draw() {
        writefln("Drawing Square at (%s,%s) with width %s", x, y, width);
    }
}

void main() {
    auto order = [Circle.classinfo, Square.classinfo]; // the order in which to draw the shapes

    auto shapes = [cast(Shape)(new Circle(1,1,5)), new Square(2,4,3),
                   new Circle(3,3,7), new Square(4,2,4)];

    shapes.sort((Shape s){ return findPos((cast(Object)s).classinfo, order); });

    foreach (shape; shapes)
        shape.draw();
}

It uses sort() and findPos(), but similar functions are probably present in Tango too, the first sorts an array according to a key function, and the second gives the index of an item into an iterable or -1 if absent.

If the 'order' array becomes too much long it can of course be replaced by an associative array, that gives a faster lookup.

Bye,
bearophile
September 27, 2008
Sat, 27 Sep 2008 19:50:18 +0200,
torhu wrote:
> obj.classinfo doesn't work the way you'd expect with an interface, but it works when you've got an object:
> 
> writefln((cast(Object)thing).classinfo.name);

Thanks for the tip!  It seems like classinfo of an interface contains information about the most derived interface implemented in an object:

interface a {}
interface aa : a {}
class A : aa {}
void main() {
    writefln((cast(a) new A).classinfo.name);
}

prints "test.aa".  Though this functionality is of questionable usefulness (has anybody used it for something?) and besides it's broken:

interface a {}
interface aa : a {}
class A : a, aa {}
void main() {
    writefln((cast(a) new A).classinfo.name);
}

prints "test.a" even though A implements the "aa" interface as well.
September 27, 2008
Sergey Gromov wrote:
> Sat, 27 Sep 2008 19:50:18 +0200,
> torhu wrote:
>> obj.classinfo doesn't work the way you'd expect with an interface, but it works when you've got an object:
>>
>> writefln((cast(Object)thing).classinfo.name);
> 
> Thanks for the tip!  It seems like classinfo of an interface contains information about the most derived interface implemented in an object:
> 
> interface a {}
> interface aa : a {}
> class A : aa {}
> void main() {
>     writefln((cast(a) new A).classinfo.name);
> }
> 
> prints "test.aa".  Though this functionality is of questionable usefulness (has anybody used it for something?) and besides it's broken:
> 
> interface a {}
> interface aa : a {}
> class A : a, aa {}
> void main() {
>     writefln((cast(a) new A).classinfo.name);
> }
> 
> prints "test.a" even though A implements the "aa" interface as well.

Since .classinfo is essentially a virtual call, and interface vtbls are filled from the class's vtbl, it shouldn't in theory be terribly difficult to change this. Of course, I'd have to check the dmd source to be sure.
September 28, 2008
Sat, 27 Sep 2008 19:21:56 -0400,
Christopher Wright wrote:
> Sergey Gromov wrote:
> > Sat, 27 Sep 2008 19:50:18 +0200,
> > torhu wrote:
> >> obj.classinfo doesn't work the way you'd expect with an interface, but it works when you've got an object:
> >>
> >> writefln((cast(Object)thing).classinfo.name);
> > 
> > Thanks for the tip!  It seems like classinfo of an interface contains information about the most derived interface implemented in an object:
> > 
> > interface a {}
> > interface aa : a {}
> > class A : aa {}
> > void main() {
> >     writefln((cast(a) new A).classinfo.name);
> > }
> > 
> > prints "test.aa".  Though this functionality is of questionable usefulness (has anybody used it for something?) and besides it's broken:
> > 
> > interface a {}
> > interface aa : a {}
> > class A : a, aa {}
> > void main() {
> >     writefln((cast(a) new A).classinfo.name);
> > }
> > 
> > prints "test.a" even though A implements the "aa" interface as well.
> 
> Since .classinfo is essentially a virtual call, and interface vtbls are filled from the class's vtbl, it shouldn't in theory be terribly difficult to change this. Of course, I'd have to check the dmd source to be sure.

I'd say it's a bug.  Classinfo is for runtime class, and runtime class can never be an interface.
September 28, 2008
Sergey Gromov:
> I'd say it's a bug.  Classinfo is for runtime class, and runtime class can never be an interface.

It seems all my questions in this newsgroup end with the discovery of another possible (and often real) bug ;-]

If it's not a bug, then I think a nicer syntax may be appreciable. In such thing Java may show some better syntax (well, better method name essentially, so better API and not really better syntax).

Bye and thank you,
bearophile
« First   ‹ Prev
1 2