Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 18, 2013 Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
I am trying to do this: import std.stdio; import std.conv; class Bar{ } class Foo : Bar{ int val = 10; } class Foos : Bar{ int val = 20; string str = "some more memory"; } void main(){ Bar[] bars; bars ~= new Foo(); bars ~= new Foos(); foreach(Bar b; bars){ //writeln(b.val);//error: no property 'val' for type 'mod.Bar' } writeln(to!(Foo)(bars[0]).val);//works } The problem is that I have to cast each Bar instance to its base class (Foo, Foos) before the compiler recognizes the val variable. Is there some syntax or keyword to allow me to specify that the b in the foreach loop refers to the base class not the super, such as writeln(b.base.val); I know I can cast, but how do I know what base class each b in the foreach loop is? |
June 18, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stephen Jones | On 06/18/2013 03:10 PM, Stephen Jones wrote:
> I am trying to do this:
>
> import std.stdio;
> import std.conv;
>
> class Bar{
> }
>
> class Foo : Bar{
> int val = 10;
> }
> class Foos : Bar{
> int val = 20;
> string str = "some more memory";
> }
>
> void main(){
> Bar[] bars;
>
> bars ~= new Foo();
> bars ~= new Foos();
>
> foreach(Bar b; bars){
> //writeln(b.val);//error: no property 'val' for type 'mod.Bar'
> }
>
> writeln(to!(Foo)(bars[0]).val);//works
> }
>
> The problem is that I have to cast each Bar instance to its base class
> (Foo, Foos) before the compiler recognizes the val variable. Is there
> some syntax or keyword to allow me to specify that the b in the foreach
> loop refers to the base class not the super, such as writeln(b.base.val);
>
> I know I can cast, but how do I know what base class each b in the
> foreach loop is?
>
val() must appear on Bar. I made it an interface:
interface Bar{
int val();
}
class Foo : Bar{
int val_ = 10;
int val() {
return val_;
}
}
class Foos : Bar{
int val_ = 20;
string str = "some more memory";
int val() {
return val_;
}
}
Ali
|
June 18, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Tuesday, 18 June 2013 at 22:15:51 UTC, Ali Çehreli wrote:
> On 06/18/2013 03:10 PM, Stephen Jones wrote:
>> I am trying to do this:
>>
>> import std.stdio;
>> import std.conv;
>>
>> class Bar{
>> }
>>
>> class Foo : Bar{
>> int val = 10;
>> }
>> class Foos : Bar{
>> int val = 20;
>> string str = "some more memory";
>> }
>>
>> void main(){
>> Bar[] bars;
>>
>> bars ~= new Foo();
>> bars ~= new Foos();
>>
>> foreach(Bar b; bars){
>> //writeln(b.val);//error: no property 'val' for type 'mod.Bar'
>> }
>>
>> writeln(to!(Foo)(bars[0]).val);//works
>> }
>>
>> The problem is that I have to cast each Bar instance to its base class
>> (Foo, Foos) before the compiler recognizes the val variable. Is there
>> some syntax or keyword to allow me to specify that the b in the foreach
>> loop refers to the base class not the super, such as writeln(b.base.val);
>>
>> I know I can cast, but how do I know what base class each b in the
>> foreach loop is?
>>
>
> val() must appear on Bar. I made it an interface:
>
> interface Bar{
> int val();
> }
>
> class Foo : Bar{
> int val_ = 10;
>
> int val() {
> return val_;
> }
> }
> class Foos : Bar{
> int val_ = 20;
> string str = "some more memory";
>
> int val() {
> return val_;
> }
> }
>
> Ali
Thanks Ali
|
June 18, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stephen Jones | I iterated on Ali's solution with more OOP to demonstrate features you may find interesting. import std.stdio; interface IBar { @property int val(); } class Bar : IBar { protected int _val; @property int val() { return this._val; } } class Foo : Bar { this() { this._val = 10; } } class Foos : Bar { string str = "some more memory"; this() { this._val = 20; } } void main() { IBar[] bars; // <--- collection of objects conforming to your interface. bars ~= new Foo(); bars ~= new Foos(); foreach(IBar b; bars) { writeln(b.val); } } |
June 18, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stephen Jones | On Tue, 18 Jun 2013 18:10:49 -0400, Stephen Jones <siwenjo@gmail.com> wrote:
> I know I can cast, but how do I know what base class each b in the foreach loop is?
Just an FYI, you are using the wrong terminology. In this case, Bar is the base class, and Foo and Foos are the *derived* classes.
Other than that, I think Ali gave you the best solution.
If you wanted to do something that *wasn't* common between two derived classes (i.e. some function/member that was only on one specific derived class), you can use a nice technique called auto-casting:
if(auto der = cast(Foo)b)
{
// use Foo specific functionality on der
}
else if (auto der = cast(Foos)b)
{
// use Foos specific functionality on der
}
Hm... would be a nice idiom to implement generically in D. Like a type switch.
-Steve
|
June 19, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 2013-06-19 00:54, Steven Schveighoffer wrote: > Hm... would be a nice idiom to implement generically in D. Like a type > switch. Pattern matching :) You could quite easily implement something like this in library code: match(b, (Foo f) => ,// use f (Foos fs) => // use fs ); -- /Jacob Carlborg |
June 19, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 2013-06-19 00:15, Ali Çehreli wrote: > val() must appear on Bar. I made it an interface: > > interface Bar{ > int val(); > } > > class Foo : Bar{ > int val_ = 10; > > int val() { > return val_; > } > } > class Foos : Bar{ > int val_ = 20; > string str = "some more memory"; > > int val() { > return val_; > } > } Why not just move "val" to the base class. -- /Jacob Carlborg |
June 19, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | > Hm... would be a nice idiom to implement generically in D. Like a type switch. > > -Steve That is what I would prefer, but I tried: writeln(to!(typeof(bars[1]))(bars[1]).val); to see if I could access the "DERIVED" (thanks) class type but even though bars[1] is initialized as a new Foos its type is still marked as Bar. So the question is, how do you find the derived class type when presented with only the super class? |
June 19, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stephen Jones | On 06/19/2013 04:10 PM, Stephen Jones wrote: >> Hm... would be a nice idiom to implement generically in D. Like a type >> switch. >> >> -Steve > > That is what I would prefer, but I tried: > > writeln(to!(typeof(bars[1]))(bars[1]).val); > > to see if I could access the "DERIVED" (thanks) class type but even > though bars[1] is initialized as a new Foos its type is still marked as > Bar. So the question is, how do you find the derived class type when > presented with only the super class? typeid gives you a TypeInfo class: http://dlang.org/expression.html#TypeidExpression http://dlang.org/phobos/object.html#.TypeInfo import std.stdio; class Base {} class Derived1 : Base {} class Derived2 : Base {} void foo(Base b) { writeln(typeid(b)); } void main() { foo(new Derived1()); foo(new Derived2()); } Prints: deneme.Derived1 deneme.Derived2 There is also TypeInfo_Class there which may be useful. Ali |
June 20, 2013 Re: Is there a keyword to access the base class | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | It seems: string me = (typeid(bars[1])).toString; if(endsWith(me, "Foos")) writeln(to!(Foos)(bars[1]).val); I see there is another post where somebody has asked if they can use cast(typeof(typeid(bars[1]))).val, and it was explained that the compiler won't know typeid until after compilation but it needs typeof at compilation, so that doesn't work. So it seems a string comparison is required (hopefully I am wrong on this). Thus it seems a choice of three or four reasonably off choices all because dmd is missing a keyword (maybe "derived") that would act like the keyword super but in the other direction; if the compiler can sus out the super from the derived at compile time then it necessarily knows what the derived is. The options are accept property syntax and add an interface, which means introducing extraneous copies of functions and oddly duplicate variable names that invite all manner of bugs. Define variables which are to be used from the derived class in the base class and spend hours scratching your head about where the variable you are looking at in the derived class has been declared, then remembering and spending ages flipping from derived to base class to see what is going on. Perform string operations to discover what the actual derived type is and then cast the base to its initialized type. Wouldn't it be easier to simply write bars[1].derived.val and let the compiler look to and accept val if it is declared in the derived class, else gracefully accept val if it is only declared in the base class? |
Copyright © 1999-2021 by the D Language Foundation