www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Avoiding abstract

reply Oliver Ruebenkoenig <oliver.ruebenkoenig web.de> writes:
Hi everyone,

the following code does what i want. I was wondering if the same out put can be
produced without having the abstract char [] rawSymName(); in the Expr class?
Thanks for any hints and thoughts,

Oliver



import std.stdio;

Expr mySymbol;

public class Expr {
public
    abstract char [] rawSymName();
    abstract Expr head();
}


class Symbol : public Expr {
public 
    this( char [] name ) { 
        this.itsName = name;
    }   
    Expr head() { return mySymbol; }
    char [] rawSymName () {
        return this.itsName;
    }   
private
    char [] itsName;
}

int main( char [][] arg ) { 

    Expr myString;

    mySymbol = new Symbol("Symbol");
    myString = new Symbol("String");

    writefln(mySymbol.rawSymName() );
    writefln(mySymbol.head().rawSymName() );
    writefln(mySymbol.head().head().rawSymName() );

    writefln(myString.head().head().rawSymName() );
    
    return 0;
}
May 30 2007
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Oliver Ruebenkoenig wrote:
 Hi everyone,
 
 the following code does what i want. I was wondering if the same out put can
be produced without having the abstract char [] rawSymName(); in the Expr
class? Thanks for any hints and thoughts,

It looks like rawSymName() does something very similar to Object.toString(). So given that, why not reuse that one? As an added bonus, your writefln() calls get shorter because it automatically calls toString() on Object parameters. --- import std.stdio; Expr mySymbol; public class Expr { public abstract Expr head(); } class Symbol : public Expr { public this( char [] name ) { this.itsName = name; } Expr head() { return mySymbol; } char [] toString () { return this.itsName; } private char [] itsName; } int main( char [][] arg ) { Expr myString; mySymbol = new Symbol("Symbol"); myString = new Symbol("String"); writefln(mySymbol ); writefln(mySymbol.head() ); writefln(mySymbol.head().head() ); writefln(myString.head().head() ); return 0; } --- Of course, this isn't very helpful if you were already using toString for another representation of your objects...
May 30 2007
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Oliver Ruebenkoenig" <oliver.ruebenkoenig web.de> wrote in message 
news:f3kdri$ap4$1 digitalmars.com...
 Hi everyone,

 the following code does what i want. I was wondering if the same out put 
 can be produced without having the abstract char [] rawSymName(); in the 
 Expr class? Thanks for any hints and thoughts,

 Oliver

Why do you want to avoid abstract?
 class Symbol : public Expr {
 public
    this( char [] name ) {
        this.itsName = name;
    }
    Expr head() { return mySymbol; }
    char [] rawSymName () {
        return this.itsName;
    }
 private
    char [] itsName;
 }

By the way, writing a protection attribute without a colon after it will only affect the immediately-following declaration. So the public in this class only affects "this". head and rawSymName are public but only because the default protection is public. Similarly private only affects itsName; if you were to add other members after itsName, they would be public. It looks like you want: class Symbol : public Expr { public: this( char [] name ) { this.itsName = name; } Expr head() { return mySymbol; } char [] rawSymName () { return this.itsName; } private: char [] itsName; }
May 30 2007
parent reply Oliver Ruebenkoenig <oliver.ruebenkoenig web.de> writes:
Jarrett Billingsley Wrote:

 "Oliver Ruebenkoenig" <oliver.ruebenkoenig web.de> wrote in message 
 news:f3kdri$ap4$1 digitalmars.com...
 Hi everyone,

 the following code does what i want. I was wondering if the same out put 
 can be produced without having the abstract char [] rawSymName(); in the 
 Expr class? Thanks for any hints and thoughts,

 Oliver

Why do you want to avoid abstract?

If i derive another class, say Integer i'd have to insert something like abstract int val(); for the value of the Integer. Now, I do not want specify an Integer for my Symbol and like wise i do not need a char [] in my Integer. How can i do this? The only thing the expressions share is their virtual head. the following code does NOT work but shows the problem - i hope ;-) thanks for the comments concerning the public: and private: Oliver import std.stdio; Expr mySymbol; Expr myInteger; public class Expr { public: abstract char [] rawSymName(); abstract int val(); abstract Expr head(); } class Symbol : public Expr { public: this( char [] name ) { this.itsName = name; } Expr head() { return mySymbol; } char [] rawSymName() { return this.itsName; } private: char [] itsName; } class Integer : public Expr { public: this( int value ) { this.itsValue = value; } Expr head() { return myInteger; } int val() { return this.itsValue; } private: int itsValue; } int main( char [][] arg ) { Expr myString; Expr myInt; mySymbol = new Symbol("Symbol"); myString = new Symbol("String"); myInteger = new Symbol("Integer"); anInt = new Integer(42); writefln(mySymbol.rawSymName() ); writefln(mySymbol.head().rawSymName() ); writefln(mySymbol.head().head().rawSymName() ); writefln(myString.head().head().rawSymName() ); writefln(myInteger.head().rawSymName() ); // writefln(anInt.val() ); return 0; }
May 30 2007
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Oliver Ruebenkoenig" <oliver.ruebenkoenig web.de> wrote in message 
news:f3khn7$hjf$1 digitalmars.com...

 If i derive another class, say Integer i'd have to insert something like 
 abstract int val(); for the value of the Integer. Now, I do not want 
 specify an Integer for my Symbol and like wise i do not need a char []  in 
 my Integer. How can i do this? The only thing the expressions share is 
 their virtual head.

 the following code does NOT work but shows the problem - i hope ;-)

If you don't want int val() to have to be declared in every class, then only declare it in the classes that you need. In your case, only declare it in Integer. What on earth is .head() for anyway?
May 30 2007
prev sibling parent reply =?ISO-8859-1?Q?Oliver_R=fcbenk=f6nig?= <oliver.ruebenkoenig web.de> writes:
Thanks for all the comments. They helped me a  great deal to better understand
what i wanted to do. I put the working code below.

I am just playing around with data structures. Using a head/tag of the datum is
also experimental.

Thanks again,
Oliver


-------------

import std.stdio;

interface Expr {
    Expr head();
    void print();
}

Expr steSymbol;

class Symbol : Expr { 
public:
    this(char [] name) { this.itsName = name; }
    char [] getName() { return this.itsName; }
    Expr head() {return steSymbol;}
    void print() {writefln(this.itsName);}
private:
    char [] itsName;    
}

int main ( char [][] arg ) { 
    Expr e;
    steSymbol = new Symbol("Symbol");
    e = new Symbol("x");
    steSymbol.print();
    e.print();
    e.head().print();
    return 0;
}

Henning Hasemann Wrote:

 
 If I got you right your problem is: You want to use specific methods of
 derived objects without having to cast them for easy access.
 But you only have a base-class reference available because the method
 that returns the "head" (whatever that means in your case) is available
 in all classes and declared in your base class.
 
 I would try this:
 
 * Implement head() in your base class, throwing an exception
 * Derive head but return exactly the type you want to return
 
 If that doesnt work, because you dont know what head() will return
 for each class in advance, let them all return Expr (as you do now)
 and implement your rawSymName() etc... methods in the base class
 throwing an exception by default.
 Now you only need to override them where you actually need them.
 
 Only problem with this is, that the virtual dispatch is done at
 runtime, so you can theoretically never be sure if you will get
 a runtime error somewhen because of a typo or something.
 
 Henning
 
 -- 
 GPG Public Key: http://keyserver.veridis.com:11371/search?q=0x41911851
 Fingerprint: 344F 4072 F038 BB9E B35D  E6AB DDD6 D36D 4191 1851

Jun 01 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Something else you might want to look at is how std.socket manages to return a
TcpSocket or UdpSocket from it's base class Socket method 'accept'.

The trick/magic is in the accepting() method which the derived class overrides,
internally it creates a new derived class (TcpSocket, UdpSocket) returning it
as a base class (Socket) reference to the base class 'accept' call which then
assigns the internal socket handle and returns it.

You could do something very similar.

Regan Heath
Jun 01 2007
parent =?ISO-8859-1?Q?Oliver_R=fcbenk=f6nig?= <oliver.ruebenkoenig web.de.REMOVE> writes:
Regan Heath Wrote:

 Something else you might want to look at is how std.socket manages to return a
TcpSocket or UdpSocket from it's base class Socket method 'accept'.
 
 The trick/magic is in the accepting() method which the derived class
overrides, internally it creates a new derived class (TcpSocket, UdpSocket)
returning it as a base class (Socket) reference to the base class 'accept' call
which then assigns the internal socket handle and returns it.
 
 You could do something very similar.

That sounds interesting. Thanks for the hint. I will have a look at it. Oliver
 
 Regan Heath

Jun 04 2007
prev sibling parent Henning Hasemann <hhasemann web.de> writes:
If I got you right your problem is: You want to use specific methods of
derived objects without having to cast them for easy access.
But you only have a base-class reference available because the method
that returns the "head" (whatever that means in your case) is available
in all classes and declared in your base class.

I would try this:

* Implement head() in your base class, throwing an exception
* Derive head but return exactly the type you want to return

If that doesnt work, because you dont know what head() will return
for each class in advance, let them all return Expr (as you do now)
and implement your rawSymName() etc... methods in the base class
throwing an exception by default.
Now you only need to override them where you actually need them.

Only problem with this is, that the virtual dispatch is done at
runtime, so you can theoretically never be sure if you will get
a runtime error somewhen because of a typo or something.

Henning

-- 
GPG Public Key: http://keyserver.veridis.com:11371/search?q=0x41911851
Fingerprint: 344F 4072 F038 BB9E B35D  E6AB DDD6 D36D 4191 1851
Jun 01 2007