www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem using Interfce

reply "Stephen Jones" <siwenjo gmail.com> writes:
I have a Widget interface which I was hoping would allow me to
subsume a set of classes {Button, Cursor, etc} as being Widgets
so I could keep an array of buttons, cursors, etc by initializing
them as Widgets.

private Widget[] widgets;
...
widgets[widx++]=new Button(fmt, unitw, unith, count);
...
widgets[widx++]=new Cursor(unitw, unith, count);


But when I try to step through the array I cannot access Button
or Cursor variables because "Error: no property 'vertStart' for
type 'Widget.Widget'":

foreach(Widget w; widgets){
     glDrawArrays(GL_TRIANGLES, w.vertStart, w.vertCount);
}


I am used to languages where the w under consideration in any
iteration would be known to have been initialized as a Button or
Cursor, etc, and the value of vertStart would be found without
error. I cannot cast without wrapping everything in if
statements. I could use access functions but I would prefer not
to incur function overhead. Is there a solution?
May 14 2012
next sibling parent "John Chapman" <johnch_atms hotmail.com> writes:
On Monday, 14 May 2012 at 11:08:09 UTC, Stephen Jones wrote:
 I have a Widget interface which I was hoping would allow me to
 subsume a set of classes {Button, Cursor, etc} as being Widgets
 so I could keep an array of buttons, cursors, etc by 
 initializing
 them as Widgets.

 private Widget[] widgets;
 ...
 widgets[widx++]=new Button(fmt, unitw, unith, count);
 ...
 widgets[widx++]=new Cursor(unitw, unith, count);


 But when I try to step through the array I cannot access Button
 or Cursor variables because "Error: no property 'vertStart' for
 type 'Widget.Widget'":

 foreach(Widget w; widgets){
     glDrawArrays(GL_TRIANGLES, w.vertStart, w.vertCount);
 }


 I am used to languages where the w under consideration in any
 iteration would be known to have been initialized as a Button or
 Cursor, etc, and the value of vertStart would be found without
 error. I cannot cast without wrapping everything in if
 statements. I could use access functions but I would prefer not
 to incur function overhead. Is there a solution?

Are you compiling with the -property switch? If so, vertStart and vertCount must be declared with the property attribute. Otherwise invoke them like regular functions, i.e., vertStart() / vertCount().
May 14 2012
prev sibling next sibling parent reply simendsjo <simendsjo gmail.com> writes:
On Mon, 14 May 2012 13:08:06 +0200, Stephen Jones <siwenjo gmail.com>  
wrote:

 I have a Widget interface which I was hoping would allow me to
 subsume a set of classes {Button, Cursor, etc} as being Widgets
 so I could keep an array of buttons, cursors, etc by initializing
 them as Widgets.

 private Widget[] widgets;
 ...
 widgets[widx++]=new Button(fmt, unitw, unith, count);
 ...
 widgets[widx++]=new Cursor(unitw, unith, count);


 But when I try to step through the array I cannot access Button
 or Cursor variables because "Error: no property 'vertStart' for
 type 'Widget.Widget'":

 foreach(Widget w; widgets){
      glDrawArrays(GL_TRIANGLES, w.vertStart, w.vertCount);
 }


 I am used to languages where the w under consideration in any
 iteration would be known to have been initialized as a Button or
 Cursor, etc, and the value of vertStart would be found without
 error. I cannot cast without wrapping everything in if
 statements. I could use access functions but I would prefer not
 to incur function overhead. Is there a solution?

If the language/runtime knows the actual underlying class for the interface, some overhead must occur behind the scenes. This seems more like a design issue. Why doesn't the interface contain vertStart etc? Should you have a base class that contains these? Or another interface? import std.algorithm, std.stdio; interface Widget {} // common widget class SomeWidget : Widget {} interface VerticeWidget : Widget { // Might be drawn property int vertStart(); } class Button : VerticeWidget { property int vertStart() { return 10; } } // only fetch VerticeWidgets property auto verticeWidgets(Widget[] widgets) { return widgets .map!((a) => cast(VerticeWidget)a)() .filter!((a) => a !is null)(); } void main() { Widget[] widgets; widgets ~= new SomeWidget(); widgets ~= new Button(); widgets ~= new SomeWidget(); // this only includes the Button (prints 10), which has vertStart as it derives from VerticeWidget foreach(widget; widgets.verticeWidgets) { writeln(widget.vertStart); } } /
May 14 2012
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/14/2012 11:40 AM, Stephen Jones wrote:
 I want an array of different classes of objects.

So far, Object[] makes sense.
 I tried to
 subsume the differences by extending the classes under a single
 interface/abstract class/super class (3 different approaches) all
 to no avail

Yeah, that is a fundamental example of object oriented design. Thank you for showing us some code below. It help a lot.
 as I could not access the public variables of the
 instantiated classes while storing them in an array defined by
 the interface/super class.

Makes sense because neither the interface nor the super class has such members. D's polymorphism does not have virtual values (nor does C++'s, the other object oriented language that I know well). Polymorphism is about virtual member functions. What you can do is to force the subclasses provide the data through virtual functions. (An alternative is to use compile-time polymorphism through templates. They provide data virtualization. (See range interfaces like InputRange. For example, the return type of front() is not specified by InputRange. Ranges can be of any type of elements.))
 interface Widget{
 void draw();
 }

 class Button : Widget{
 public int vertCount;

 void draw(){}
 }

 class Cursor : Widget{
 public int vertCount;

 void draw(){}
 }

 //called from
 Widget[] widgets;
 widgets~=new Button();
 widgets~=new Cursor();

 foreach(Widget w; widgets){
 writeln(w.vertCount);
 }
 //Error: no property 'vertCount' for type 'Widget.Widget'

I've wrapped your code inside void main() and added import std.stdio. Then I got a different error: Error: undefined identifier 'vertCount' But it makes sense, right? Widget does not have vertCount. The following works because the Widget interface mandates that the subclasses provide such a property: import std.stdio; interface Widget{ void draw(); int vertCount() property; // <-- added } class Button : Widget{ public int vertCount_; void draw(){} int vertCount() const property { return vertCount_; } } class Cursor : Widget{ public int vertCount_; void draw(){} int vertCount() const property { return vertCount_; } } void main() { //called from Widget[] widgets; widgets~=new Button(); widgets~=new Cursor(); foreach(Widget w; widgets){ writeln(w.vertCount); } }
 A solution that should work is to dump extending the classes and
 make an array of void pointers that point, some to Button objects
 and some to Cursors but I do not know the syntax for doing this,
 or even if it is possible to have an array of pointers pointing
 at different classes of objects. I should think it should be
 possible given that, on a 32 bit machine, pointers are all 32 bit
 ints so it is basically an array of ints that is being created,
 only those ints contain the address of a bunch of different types
 of objects.

Yes, all that is possible too. Ali -- D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html
May 14 2012
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/14/2012 11:49 AM, Stephen Jones wrote:

 My
 understanding is that c# getter setters were simply syntactic sugar
 which under the hood called standard functions incurring the standard
 function overhead. Is this the same with D, or does D implement
 properties using pointers to the required data fields?

It is the same with D but the compiler can optimize out the function call in cases where that is possible. Ali -- D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html
May 14 2012
parent Ary Manzana <ary esperanto.org.ar> writes:
On 5/16/12 9:24 AM, Stephen Jones wrote:
 Ary: I seem to remember playing around with a Simpsons extending program
 in Java that did this; you could throw all the different Simpsons into a
 single Array because they extended "Simpson", and you could walk through
 the array and each would call their own name. I kind of purposely left
 the language vague in case I was mistaken.

But in Java you'd also need to cast the Simpson to a specific class if it contains the fields you are interested it.
May 16 2012
prev sibling next sibling parent "Stephen Jones" <siwenjo gmail.com> writes:
On Monday, 14 May 2012 at 11:49:21 UTC, simendsjo wrote:
 On Mon, 14 May 2012 13:08:06 +0200, Stephen Jones 
 <siwenjo gmail.com> wrote:

 I have a Widget interface which I was hoping would allow me to
 subsume a set of classes {Button, Cursor, etc} as being Widgets
 so I could keep an array of buttons, cursors, etc by 
 initializing
 them as Widgets.

 private Widget[] widgets;
 ...
 widgets[widx++]=new Button(fmt, unitw, unith, count);
 ...
 widgets[widx++]=new Cursor(unitw, unith, count);


 But when I try to step through the array I cannot access Button
 or Cursor variables because "Error: no property 'vertStart' for
 type 'Widget.Widget'":

 foreach(Widget w; widgets){
     glDrawArrays(GL_TRIANGLES, w.vertStart, w.vertCount);
 }


 I am used to languages where the w under consideration in any
 iteration would be known to have been initialized as a Button 
 or
 Cursor, etc, and the value of vertStart would be found without
 error. I cannot cast without wrapping everything in if
 statements. I could use access functions but I would prefer not
 to incur function overhead. Is there a solution?

If the language/runtime knows the actual underlying class for the interface, some overhead must occur behind the scenes. This seems more like a design issue. Why doesn't the interface contain vertStart etc? Should you have a base class that contains these? Or another interface? import std.algorithm, std.stdio; interface Widget {} // common widget class SomeWidget : Widget {} interface VerticeWidget : Widget { // Might be drawn property int vertStart(); } class Button : VerticeWidget { property int vertStart() { return 10; } } // only fetch VerticeWidgets property auto verticeWidgets(Widget[] widgets) { return widgets .map!((a) => cast(VerticeWidget)a)() .filter!((a) => a !is null)(); } void main() { Widget[] widgets; widgets ~= new SomeWidget(); widgets ~= new Button(); widgets ~= new SomeWidget(); // this only includes the Button (prints 10), which has vertStart as it derives from VerticeWidget foreach(widget; widgets.verticeWidgets) { writeln(widget.vertStart); } } /

I haven't been clear, vertStart and vertCount are variables not functions: public int vertStart, vertCount=6; A solution that should work is to dump extending the classes and make an array of void pointers that point, some to Button objects, and some to Cursor objects but I do not know the syntax for doing this, or even if it is possible to have an array of pointers pointing at different classes of objects. I should think it should be possible given that, on a 32 bit machine, pointers are all 32 bit ints so it is basically an array of ints that is being created, only those ints contain the address of a bunch of different types of objects. Thankyou simendsjo for the code you provided it has helped on other matters.
May 14 2012
prev sibling next sibling parent "Stephen Jones" <siwenjo gmail.com> writes:
On Monday, 14 May 2012 at 18:39:13 UTC, Stephen Jones wrote:
 On Monday, 14 May 2012 at 11:49:21 UTC, simendsjo wrote:
 On Mon, 14 May 2012 13:08:06 +0200, Stephen Jones 
 <siwenjo gmail.com> wrote:

 I have a Widget interface which I was hoping would allow me to
 subsume a set of classes {Button, Cursor, etc} as being 
 Widgets
 so I could keep an array of buttons, cursors, etc by 
 initializing
 them as Widgets.

 private Widget[] widgets;
 ...
 widgets[widx++]=new Button(fmt, unitw, unith, count);
 ...
 widgets[widx++]=new Cursor(unitw, unith, count);


 But when I try to step through the array I cannot access 
 Button
 or Cursor variables because "Error: no property 'vertStart' 
 for
 type 'Widget.Widget'":

 foreach(Widget w; widgets){
    glDrawArrays(GL_TRIANGLES, w.vertStart, w.vertCount);
 }


 I am used to languages where the w under consideration in any
 iteration would be known to have been initialized as a Button 
 or
 Cursor, etc, and the value of vertStart would be found without
 error. I cannot cast without wrapping everything in if
 statements. I could use access functions but I would prefer 
 not
 to incur function overhead. Is there a solution?

If the language/runtime knows the actual underlying class for the interface, some overhead must occur behind the scenes. This seems more like a design issue. Why doesn't the interface contain vertStart etc? Should you have a base class that contains these? Or another interface? import std.algorithm, std.stdio; interface Widget {} // common widget class SomeWidget : Widget {} interface VerticeWidget : Widget { // Might be drawn property int vertStart(); } class Button : VerticeWidget { property int vertStart() { return 10; } } // only fetch VerticeWidgets property auto verticeWidgets(Widget[] widgets) { return widgets .map!((a) => cast(VerticeWidget)a)() .filter!((a) => a !is null)(); } void main() { Widget[] widgets; widgets ~= new SomeWidget(); widgets ~= new Button(); widgets ~= new SomeWidget(); // this only includes the Button (prints 10), which has vertStart as it derives from VerticeWidget foreach(widget; widgets.verticeWidgets) { writeln(widget.vertStart); } } /

I haven't been clear, vertStart and vertCount are variables not functions: public int vertStart, vertCount=6; A solution that should work is to dump extending the classes and make an array of void pointers that point, some to Button objects, and some to Cursor objects but I do not know the syntax for doing this, or even if it is possible to have an array of pointers pointing at different classes of objects. I should think it should be possible given that, on a 32 bit machine, pointers are all 32 bit ints so it is basically an array of ints that is being created, only those ints contain the address of a bunch of different types of objects. Thankyou simendsjo for the code you provided it has helped on other matters.

Sorry, no edit functionality. I have just been re-reading property syntax and see it is the same as c# getter setter deals. My understanding is that c# getter setters were simply syntactic sugar which under the hood called standard functions incurring the standard function overhead. Is this the same with D, or does D implement properties using pointers to the required data fields?
May 14 2012
prev sibling next sibling parent Ary Manzana <ary esperanto.org.ar> writes:
On 5/14/12 6:08 PM, Stephen Jones wrote:
 I am used to languages where the w under consideration in any
 iteration would be known to have been initialized as a Button or
 Cursor, etc, and the value of vertStart would be found without
 error.

What are the names of those languages?
May 15 2012
prev sibling next sibling parent "Stephen Jones" <siwenjo gmail.com> writes:
On Monday, 14 May 2012 at 20:27:37 UTC, Ali Çehreli wrote:
 On 05/14/2012 11:49 AM, Stephen Jones wrote:

 My
 understanding is that c# getter setters were simply syntactic

 which under the hood called standard functions incurring the

 function overhead. Is this the same with D, or does D

 properties using pointers to the required data fields?

It is the same with D but the compiler can optimize out the function call in cases where that is possible. Ali

Thanks Ali for the syntax, some very useful bits and pieces I did not know. I do not want to use property syntax. Form a performance perspective I cannot see any good reason not to simply use an array of pointers to the different objects (buttons, cursor, etc) rather than incurring function overheads. Except for the good reason that I do not know the syntax. Ary: I seem to remember playing around with a Simpsons extending program in Java that did this; you could throw all the different Simpsons into a single Array because they extended "Simpson", and you could walk through the array and each would call their own name. I kind of purposely left the language vague in case I was mistaken.
May 15 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, May 16, 2012 at 04:24:12AM +0200, Stephen Jones wrote:
[...]
 Thanks Ali for the syntax, some very useful bits and pieces I did
 not know. I do not want to use property syntax. Form a performance
 perspective I cannot see any good reason not to simply use an array
 of pointers to the different objects (buttons, cursor, etc) rather
 than incurring function overheads. Except for the good reason that I
 do not know the syntax.
 
 Ary: I seem to remember playing around with a Simpsons extending
 program in Java that did this; you could throw all the different
 Simpsons into a single Array because they extended "Simpson", and
 you could walk through the array and each would call their own name.
 I kind of purposely left the language vague in case I was mistaken.

Here: class Simpson { string name; } class Bart : Simpson { this() { name = "Bart Simpson"; } } class Homer : Simpson { this() { name = "Homer Simpson"; } } void main() { Simpson[] simpsons; foreach (simpson; simpsons) { writeln(simson.name); } } T -- PNP = Plug 'N' Pray
May 15 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
Gah, I need to proof-read my code before posting. Here's the corrected
version:

 	class Simpson {
 		string name;
 	}
 	class Bart : Simpson {
 		this() {
 			name = "Bart Simpson";
 		}
 	}
 	class Homer : Simpson {
 		this() {
 			name = "Homer Simpson";
 		}
 	}
 
 	void main() {
 		Simpson[] simpsons = [
			new Bart,
			new Homer
		];
 
 		foreach (simpson; simpsons) {
 			writeln(simpson.name);
 		}
 	}
 
 
--T

-- 
My program has no bugs! Only undocumented features...
May 15 2012