Jump to page: 1 2
Thread overview
Method Blocking
Aug 13, 2003
Benji Smith
Re: Method Blocking ( they are not !!!! is this another compiler bug)
Aug 13, 2003
Mike Wynn
Re: Method Blocking
Aug 13, 2003
Jason Mills
Aug 13, 2003
Benji Smith
Aug 13, 2003
Patrick Down
Aug 13, 2003
Mike Wynn
Aug 14, 2003
Benji Smith
Aug 14, 2003
Patrick Down
Aug 14, 2003
Mike Wynn
Aug 14, 2003
Sean L. Palmer
Aug 16, 2003
Philippe Mori
August 13, 2003
Here's an idea that I've been aching for in several different languages: method blocking.

I often create base classes that will have lots of different kinds of derived classes. To avoid duplicating code, I put all the method definitions in the base class, so that they can be inherited by the derived classes that really need them. But not all of the derived classes should have access to all of the methods in the parent class, and I'd like to block them.

Take a look at this code:

class baseClass {
	public void doSomething() {
		...
	}
	public void doSomethingElse() {
		...
	}
}
class derivedClassA: baseClass {
	public void doSomethingFun() {

	}
}
class derivedClassB: baseClass {
	block void doSomething();
	public void doSomethingSilly() {

	}
}

In this example, my base class has two methods: "doSomething()" and "doSomethingElse()". The class derivedClassA inherits both of these virtual functions, but the class derivedClassB specifically blocks the use of the "doSomething()" function. Attempting to call this function should result in a compiler error, not in a runtime exception.

In the past, I've used exceptions to define class hierarchies like this. I'll define the methods that I need in the base class, and then I'll overload those functions in the derived classes, something like this:

class derivedClassB: baseClass {
	public void doSomething() {
	throw new Exception("Cannot call doSomething from a
		derivedClassB object");
	}
	public void doSomethingSilly() {

	}
}

But throwing exceptions is costly, and besides, I should be able to know AT COMPILE TIME if I'm calling methods that shouldn't exist anyhow.

I've been wishing for functionality like this for ages, and I can't fathom why it isn't available. It seems like it would be easy to use the "block" keyword to simply remove an entry from the v-table, wouldn't it?
August 13, 2003
why make base::doSomthing public if you don't want it callable from a sub class ??

by saying
class Base {
    public void func() {... }
}
you are defining the base "interface" of your object
(java has the "final" keyword to stop you redefining a functions in a super
class)
but if you realy do no want func to be called for a super class I would say
your object heirachy is wrong somewhere, or is should be

class Base {
    private void func() {... } // only callable by Base and only implemented
here
}

or protected if you want to allow the Derived classes to access them but not others.

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

import c.stdio;

class A {
 this() { printf("A::this()\n"); }
 protected void show() { printf("A::show()\n"); }
 protected void shout() { printf("A::shout()\n"); }
}

class B : A {
 this() { printf("B::this()\n"); }
 public void show() { super.show(); printf("B::show()\n"); }
}

class C : A {
 this() { printf("C::this()\n"); }
 public void shout() { super.shout(); printf("C::shout()\n"); }
}

int main( char[][] args ) {
 A b = new B();
 A c = new C();
 b.show();
 c.show();

/* // errr!!! was going to be
 B b = new B();
 C c = new C();
 b.show();
 c.shout();
*/
 return 0;
}
-----------------------------------------
for some reason this works!! but a::show is protected so should only be accesable from sub class ??

sounds to me like you are trying to write code without thinking about the oo design of you classes.

"Benji Smith" <dlanguage@xxagg.com> wrote in message news:h2ikjv8f8bf6h09fnamt6ivuehqb5401vv@4ax.com...
> Here's an idea that I've been aching for in several different languages: method blocking.
>
> I often create base classes that will have lots of different kinds of derived classes. To avoid duplicating code, I put all the method definitions in the base class, so that they can be inherited by the derived classes that really need them. But not all of the derived classes should have access to all of the methods in the parent class, and I'd like to block them.
>
> Take a look at this code:
>
> class baseClass {
> public void doSomething() {
> ...
> }
> public void doSomethingElse() {
> ...
> }
> }
> class derivedClassA: baseClass {
> public void doSomethingFun() {
>
> }
> }
> class derivedClassB: baseClass {
> block void doSomething();
> public void doSomethingSilly() {
>
> }
> }
>
> In this example, my base class has two methods: "doSomething()" and "doSomethingElse()". The class derivedClassA inherits both of these virtual functions, but the class derivedClassB specifically blocks the use of the "doSomething()" function. Attempting to call this function should result in a compiler error, not in a runtime exception.
>
> In the past, I've used exceptions to define class hierarchies like this. I'll define the methods that I need in the base class, and then I'll overload those functions in the derived classes, something like this:
>
> class derivedClassB: baseClass {
> public void doSomething() {
> throw new Exception("Cannot call doSomething from a
> derivedClassB object");
> }
> public void doSomethingSilly() {
>
> }
> }
>
> But throwing exceptions is costly, and besides, I should be able to know AT COMPILE TIME if I'm calling methods that shouldn't exist anyhow.
>
> I've been wishing for functionality like this for ages, and I can't fathom why it isn't available. It seems like it would be easy to use the "block" keyword to simply remove an entry from the v-table, wouldn't it?


August 13, 2003
Comments in line.

Mike Wynn wrote:
> why make base::doSomthing public if you don't want it callable from a sub
> class ??

What about you are not the designer of the base class, and can't modify it? For example, the base class could be a part of a library you are using. You want to specialize a class in the library but in such a way that some base methods just don't make sense anymore for the new subclass.

> by saying
> class Base {
>     public void func() {... }
> }
> you are defining the base "interface" of your object
> (java has the "final" keyword to stop you redefining a functions in a super
> class)
> but if you realy do no want func to be called for a super class I would say
> your object heirachy is wrong somewhere, or is should be
> 
> class Base {
>     private void func() {... } // only callable by Base and only implemented
> here
> }
> 
> or protected if you want to allow the Derived classes to access them but not
> others.
> 

August 13, 2003
On Wed, 13 Aug 2003 16:16:02 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:

>why make base::doSomthing public if you don't want it callable from a sub class ??

The example that I posted was a bit too simplistic. Let me tell you the real (well, almost real) situation in which I'm encountering this:

******************************************************************
class Node {
	public char[] name;
	public Node prevSibling;
	public Node nextSibling;
	public Node parent;
	public void appendChild();
	public Node getChild(int index);
	public void removeChild(int index);
}

class Document: Node {
	public char[] version;
	public char[] encoding;
	public char[] standalone;
	block Node parent;
}

class Element: Node {
	public char[char[]][] attributes;
}

class Comment: Node {
	block void appendChild();
	block void getChild();
	block void removeChild();
}
******************************************************************

Comments, Elements, and Documents are all derived classes of the superclass Node. Documents and Elements both have children, so they both need the appendChild(), getChild, and removeChild() methods. But a comment node, which is a perfectly valid type of node, doesn't have any children, so it should be able to block these methods. It doesn't need them.

Likewise, a Docment node can't have a parent, so I should be able to block the parent member.

Of course, I could implement the appendChild(), removeChild(), and getChild() methods separately in both the Document class and in the Element class, but THE CODE IS ESSENTIALLY IDENTICAL, so it doesn't make any sense for me to have that code exist in both places. I moved that code to the parent class so that both derived classes can take advantage of it.

And the Comment class need to descendants of the Node class, just like the Element and Document classes, so that I can handle them all polymorphically when linking to prevSibling and nextSibling.

So, for my XML api, it would make my life a lot easier, it would make my object hierarchy simpler, and it would make runtime performance more predictable, if I could just block methods and members that aren't needed in a particular derived class.

>but if you realy do no want func to be called for a super class I would say your object heirachy is wrong somewhere

I anticipated that type of response, but I think it's a knee-jerk reaction that isn't necessarily correct. That's like saying "if you have to ADD member functions to a child class, maybe the class hierarchy is wrong."

A derived class can _ADD_ new members to the members inherited from the parent class. A derived class can _OVERRIDE_ existing members inherited from the parent class. So why can a derived class not _BLOCK_ access to some of the members of the parent class? This seems like a perfectly logical conclusion to me.

There's no reason to say that the derived class isn't logically a subclass of the parent class. But it's not EXACTLY THE SAME as its parent, and one of the ways that it should be able to differentiate itself is by blocking access to methods that are important to the parent but not to the child.

Am I the only one who thinks this is silly?
August 13, 2003
In article <sivkjv0nadkrv2oebehn6c0fv33ebjdo1l@4ax.com>, Benji Smith says...
>
>On Wed, 13 Aug 2003 16:16:02 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:
>
>>why make base::doSomthing public if you don't want it callable from a sub class ??
>
>The example that I posted was a bit too simplistic. Let me tell you the real (well, almost real) situation in which I'm encountering this:
>
>******************************************************************
>class Node {
>	public char[] name;
>	public Node prevSibling;
>	public Node nextSibling;
>	public Node parent;
>	public void appendChild();
>	public Node getChild(int index);
>	public void removeChild(int index);
>}
>
>class Document: Node {
>	public char[] version;
>	public char[] encoding;
>	public char[] standalone;
>	block Node parent;
>}
>
>class Element: Node {
>	public char[char[]][] attributes;
>}
>
>class Comment: Node {
>	block void appendChild();
>	block void getChild();
>	block void removeChild();
>}

What happens when you do this:

Node n = new Comment();

n.appendChild();  // Legal for Node



August 13, 2003
"Benji Smith" <dlanguage@xxagg.com> wrote in message news:sivkjv0nadkrv2oebehn6c0fv33ebjdo1l@4ax.com...
> On Wed, 13 Aug 2003 16:16:02 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:
>
> >why make base::doSomthing public if you don't want it callable from a sub class ??

class Node {}
class Doc : Node {}
class NodeWithParent : Node {
}
class Foo : NodeWithParent {
}

etc or use interfaces;
class Node { }
interface IHasParent {}
interface IHasSibling : IHasParent {} // how can you have siblings if you
ain't got a parent
interface IHasChildren {} // how can you have siblings if you ain't got a
parent

 etc ...
if you want to see the ways ppl solve this look at gui libs, (C++ :
TurboVision,MFC, WTL, WxWindows, VGUI, BeOS API) (Delphi: VCL) (Java: AWT,
Swing, IFC (if you can find it, was netscaps Swing before swing on top of
the AWT, the Eclipse/IBM SWT) )

you have a similar issue, to the gui questions of ... should componant be able to "draw" on itself, and should it have children, and where if any do the layout managers connect to.


>
> The example that I posted was a bit too simplistic. Let me tell you the real (well, almost real) situation in which I'm encountering this:
>
> ******************************************************************
> class Node {
> public char[] name;
> public Node prevSibling;
> public Node nextSibling;
> public Node parent;
> public void appendChild();
> public Node getChild(int index);
> public void removeChild(int index);
> }
>
> class Document: Node {
> public char[] version;
> public char[] encoding;
> public char[] standalone;
> block Node parent;
> }
>
> class Element: Node {
> public char[char[]][] attributes;
> }
>
> class Comment: Node {
> block void appendChild();
> block void getChild();
> block void removeChild();
> }
> ******************************************************************
>
> Comments, Elements, and Documents are all derived classes of the superclass Node. Documents and Elements both have children, so they both need the appendChild(), getChild, and removeChild() methods. But a comment node, which is a perfectly valid type of node, doesn't have any children, so it should be able to block these methods. It doesn't need them.
>
> Likewise, a Docment node can't have a parent, so I should be able to block the parent member.
>
> Of course, I could implement the appendChild(), removeChild(), and getChild() methods separately in both the Document class and in the Element class, but THE CODE IS ESSENTIALLY IDENTICAL, so it doesn't make any sense for me to have that code exist in both places. I moved that code to the parent class so that both derived classes can take advantage of it.
>
> And the Comment class need to descendants of the Node class, just like the Element and Document classes, so that I can handle them all polymorphically when linking to prevSibling and nextSibling.
>
> So, for my XML api, it would make my life a lot easier, it would make my object hierarchy simpler, and it would make runtime performance more predictable, if I could just block methods and members that aren't needed in a particular derived class.
>
> >but if you realy do no want func to be called for a super class I would
say
> >your object heirachy is wrong somewhere
>
> I anticipated that type of response, but I think it's a knee-jerk reaction that isn't necessarily correct. That's like saying "if you have to ADD member functions to a child class, maybe the class hierarchy is wrong."
>
> A derived class can _ADD_ new members to the members inherited from the parent class. A derived class can _OVERRIDE_ existing members inherited from the parent class. So why can a derived class not _BLOCK_ access to some of the members of the parent class? This seems like a perfectly logical conclusion to me.

because your saying this is not quite a subclass! if you block a member it is no longer passable as its base class because it have missing functionality.

>
> There's no reason to say that the derived class isn't logically a subclass of the parent class. But it's not EXACTLY THE SAME as its parent, and one of the ways that it should be able to differentiate itself is by blocking access to methods that are important to the parent but not to the child.
>
> Am I the only one who thinks this is silly?

no your just experiancing one of the problems with single inheritance and
static typing, with MI or dynamic typing its all possible but the price is
performance.
"your object heirachy is wrong" may be a knee-jerk reaction, but you should
question if your heirachy is right and why `Doc` can not have a parent
(obviously there has to be a Node with a "null" parent, or no parent, which
also means that it can not have any siblings too )
D has class invariants so Doc class must always have a null parent, all you
have to do is put an assert in the "setParent method of Doc to make sure its
parent can not be set, and write your code so that it can deal with
getParent() returning null (i.e. no parent).


August 14, 2003
Look at it this way.

If you have this situation:

class A
{
    public foo() {}
}

class B : A
{
    block foo() {}
}

void bar(A a) { a.foo(); }

bar(new B);

What do you suppose should happen?

Are B's now no longer "compatible" with A's interface?  If so, it isn't a "derived" class in the proper sense.

Think what would happen if you "block" a member variable from class A in class B instead.  The memory layout no longer matches, and anything expecting an A will probably fail if you give it a B instead.

With methods, it will still break, but logically instead of physically.

Deriving from a class is like a form of contract, demanding the child class remain compatible with the parent.  You're asking to be able to violate that contract, and have the compiler figure it out and realize it can no longer be cast to the base class interface?

If you just don't want to expose a base class member in the derived class, just redeclare it private (however in D you probably have to provide an implementation for it, probably should add a call to the super function so virtual calls thru the still-public parent interface work right).  I do not think D automates this like C++ does.

It seems to be a better solution would be mixins.

******************************************************************
class Parent
{
public void appendChild();
public Node getChild(int index);
public void removeChild(int index);
}

class Child
{
public Node parent;
}

class Node {
public char[] name;
public Node prevSibling;
public Node nextSibling;
}

class Document: Node, mixin Parent {
public char[] version;
public char[] encoding;
public char[] standalone;
}

class Element: Node, mixin Parent, mixin Child {
public char[char[]][] attributes;
}

class Comment: Node, mixin Child {
}
******************************************************************

However you'd need a form of dynamic cast to decide if a given Node is capable of being a Parent, or being a Child.

Walter seems against multiple inheritance, however, so I doubt anything like this will make it into D.

However you can still do it "right" using good old fashioned class design. ;)

******************************************************************
class Node {
public char[] name;
public Node prevSibling;
public Node nextSibling;
}

class ParentNode: Node
{
public void appendChild();
public Node getChild(int index);
public void removeChild(int index);
}

class ChildNode : Node
{
public Node parent;
}


class ParentChildNode: ParentNode
{
public Node parent;
}

class Document: ParentNode
{
public char[] version;
public char[] encoding;
public char[] standalone;
}

class Element: ParentChildNode
{
public char[char[]][] attributes;
}

class Comment: ChildNode
{
}
******************************************************************

However as you can guess, this solution is brittle, since it takes work to keep the class hierarchy in good shape as its structure changes.  You can see the beginnings of this in how I built ParentChildNode.  Ideally ParentChildNode would be both a ParentNode *and* a ChildNode.  It's a Pandora's Box.

Sharing code seems like such a worthy cause, but it can cause lots of problems.

Sean

"Benji Smith" <dlanguage@xxagg.com> wrote in message news:sivkjv0nadkrv2oebehn6c0fv33ebjdo1l@4ax.com...
> On Wed, 13 Aug 2003 16:16:02 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:
>
> >why make base::doSomthing public if you don't want it callable from a sub class ??
>
> The example that I posted was a bit too simplistic. Let me tell you the real (well, almost real) situation in which I'm encountering this:
>
> ******************************************************************
> class Node {
> public char[] name;
> public Node prevSibling;
> public Node nextSibling;
> public Node parent;
> public void appendChild();
> public Node getChild(int index);
> public void removeChild(int index);
> }
>
> class Document: Node {
> public char[] version;
> public char[] encoding;
> public char[] standalone;
> block Node parent;
> }
>
> class Element: Node {
> public char[char[]][] attributes;
> }
>
> class Comment: Node {
> block void appendChild();
> block void getChild();
> block void removeChild();
> }
> ******************************************************************
>
> Comments, Elements, and Documents are all derived classes of the superclass Node. Documents and Elements both have children, so they both need the appendChild(), getChild, and removeChild() methods. But a comment node, which is a perfectly valid type of node, doesn't have any children, so it should be able to block these methods. It doesn't need them.
>
> Likewise, a Docment node can't have a parent, so I should be able to block the parent member.
>
> Of course, I could implement the appendChild(), removeChild(), and getChild() methods separately in both the Document class and in the Element class, but THE CODE IS ESSENTIALLY IDENTICAL, so it doesn't make any sense for me to have that code exist in both places. I moved that code to the parent class so that both derived classes can take advantage of it.
>
> And the Comment class need to descendants of the Node class, just like the Element and Document classes, so that I can handle them all polymorphically when linking to prevSibling and nextSibling.
>
> So, for my XML api, it would make my life a lot easier, it would make my object hierarchy simpler, and it would make runtime performance more predictable, if I could just block methods and members that aren't needed in a particular derived class.
>
> >but if you realy do no want func to be called for a super class I would
say
> >your object heirachy is wrong somewhere
>
> I anticipated that type of response, but I think it's a knee-jerk reaction that isn't necessarily correct. That's like saying "if you have to ADD member functions to a child class, maybe the class hierarchy is wrong."
>
> A derived class can _ADD_ new members to the members inherited from the parent class. A derived class can _OVERRIDE_ existing members inherited from the parent class. So why can a derived class not _BLOCK_ access to some of the members of the parent class? This seems like a perfectly logical conclusion to me.
>
> There's no reason to say that the derived class isn't logically a subclass of the parent class. But it's not EXACTLY THE SAME as its parent, and one of the ways that it should be able to differentiate itself is by blocking access to methods that are important to the parent but not to the child.
>
> Am I the only one who thinks this is silly?


August 14, 2003
On Wed, 13 Aug 2003 22:21:40 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:

>
>"Benji Smith" <dlanguage@xxagg.com> wrote in message news:sivkjv0nadkrv2oebehn6c0fv33ebjdo1l@4ax.com...
>> On Wed, 13 Aug 2003 16:16:02 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:
>>
>> >why make base::doSomthing public if you don't want it callable from a sub class ??
>
>class Node {}
>class Doc : Node {}
>class NodeWithParent : Node {
>}
>class Foo : NodeWithParent {
>}
>
>etc or use interfaces;
>class Node { }
>interface IHasParent {}
>interface IHasSibling : IHasParent {} // how can you have siblings if you
>ain't got a parent
>interface IHasChildren {} // how can you have siblings if you ain't got a
>parent
>
> etc ...

What I'd really like to do is to create a class hierarchy like this...

Node
NodeWithChildren: Node
NodeWithParent: Node
Document:NodeWithChildren
Element:NodeWithParent, NodeWithChildren
Comment:NodeWithParent
Text:NodeWithParent
CDataSection:NodeWithParent
ProcessingInstruction:NodeWithParent

...but it would require mulitiple inheritance, and apparantly it becomes much more difficult to write  a compiler if it uses multiple inheritance. I suppose that NodeWithParent and NodeWithChildren could be interfaces (IHasParent and IHasChildren) rather than classes, but then I have to put the implementations of the parent-handling and children-handling methods into all of the individual classes. So, I would need to copy the parent-handling methods (which would be exactly the same in every class that uses them) five different times! The first rule of programming that I learned is DON'T HAVE THE SAME CODE IN MULTIPLE PLACES. I think that rule is more important than having a perfect object hierarchy.

So interfaces are definitely a no-win situation for me. As far as I'm concerned interfaces are mostly useful when you need to enforce a particular set of methods onto other people who will be implementing classes that will interface with your code in a particular way. But using interfaces (in this situation) won't help ME keep my own code small, manageable, and robust.

>"your object heirachy is wrong" may be a knee-jerk reaction, but you should
>question if your heirachy is right and why `Doc` can not have a parent
>(obviously there has to be a Node with a "null" parent, or no parent, which
>also means that it can not have any siblings too )
>D has class invariants so Doc class must always have a null parent, all you
>have to do is put an assert in the "setParent method of Doc to make sure its
>parent can not be set, and write your code so that it can deal with
>getParent() returning null (i.e. no parent).
>

It looks like I'll be sticking with my original strategy, throwing exceptions from the method implementations of descendant classes that shouldn't have those methods anyhow. So if you call...

myComment.appendChild(myNode);

...it will throw a...

DomException("You cannot call appendChild() from a Comment object");

It's ugly, and I don't like it, but at least it keeps me from copying the same code into five different classes. Honestly, there's got to be a better solution to this.
August 14, 2003
In article <hh6njvsmtqduiuihdels8nrmvps8ju8p27@4ax.com>, Benji Smith says...
>What I'd really like to do is to create a class hierarchy like this...
>
>Node
>NodeWithChildren: Node
>NodeWithParent: Node
>Document:NodeWithChildren
>Element:NodeWithParent, NodeWithChildren
>Comment:NodeWithParent
>Text:NodeWithParent
>CDataSection:NodeWithParent
>ProcessingInstruction:NodeWithParent
>
>...but it would require mulitiple inheritance...

Might be possible with templates


template AddParentT(T)
{
class WithParent : T
{
Node parent;
}
}

template AddChildrenT(T)
{
class WithChildren : T
{
appendChild();
getChild()
}
}

class Node {}

class Document : instance AddChildrenT(Node).WithChildren {}

class Element : instance AddParentT(
instance AddChildrenT(Node).WithChildren).WithParent { }

class Comment : instance AddParentT(Node).WithParent { }

class Text : instance AddParentT(Node).WithParent { }



August 14, 2003
"Benji Smith" <dlanguage@xxagg.com> wrote in message news:hh6njvsmtqduiuihdels8nrmvps8ju8p27@4ax.com...
> On Wed, 13 Aug 2003 22:21:40 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:
>
> >
> >"Benji Smith" <dlanguage@xxagg.com> wrote in message news:sivkjv0nadkrv2oebehn6c0fv33ebjdo1l@4ax.com...
> >> On Wed, 13 Aug 2003 16:16:02 +0100, "Mike Wynn" <mike.wynn@l8night.co.uk> wrote:
> >>
> >> >why make base::doSomthing public if you don't want it callable from a
sub
> >> >class ??
> >
> >class Node {}
> >class Doc : Node {}
> >class NodeWithParent : Node {
> >}
> >class Foo : NodeWithParent {
> >}
> >
> >etc or use interfaces;
> >class Node { }
> >interface IHasParent {}
> >interface IHasSibling : IHasParent {} // how can you have siblings if you
> >ain't got a parent
> >interface IHasChildren {} // how can you have siblings if you ain't got a
> >parent
> >
> > etc ...
>
> What I'd really like to do is to create a class hierarchy like this...
>
> Node
> NodeWithChildren: Node
> NodeWithParent: Node
> Document:NodeWithChildren
> Element:NodeWithParent, NodeWithChildren
> Comment:NodeWithParent
> Text:NodeWithParent
> CDataSection:NodeWithParent
> ProcessingInstruction:NodeWithParent
>
> ...but it would require mulitiple inheritance, and apparantly it becomes much more difficult to write  a compiler if it uses multiple inheritance. I suppose that NodeWithParent and NodeWithChildren could be interfaces (IHasParent and IHasChildren) rather than classes, but then I have to put the implementations of the parent-handling and children-handling methods into all of the individual classes. So, I would need to copy the parent-handling methods (which would be exactly the same in every class that uses them) five different times! The first rule of programming that I learned is DON'T HAVE THE SAME CODE IN MULTIPLE PLACES. I think that rule is more important than having a perfect object hierarchy.

mixin's are what you want.

you can use templates for "has children" or "group" class but D does not support lightwight templating (that is a template where the params are all objects so instances are all the same code (different cast on systems that require a cast like java)

// you could try ..
template has_children( Base : Node ) {
    class Group : Base, IGroup {
        add the child handleing code here.
    }
}
in d asfaik you have to use an interface  for the group methods to gain
acess to them
as there is no way to cast to `Group` as you dont know the type it was
created with

a language feature that would help is lightweight templating, where the
templated types are all Object (or restricted to a subclass of) and the
compiler knows the type that the template related to (great for collections)
so Stack<Node> is subclass of  Stack<Object> which is a subclass of Stack.
(like Java arrays are, [with the required runtime type checking compiled in
automatically]
kind of hybrid dynamic typechecking on a statically typed lang.

the above example could be
although code like
lightweight_template(Base : Node) class Group : Base{
        Node addChildren();
    }
}
although there are issues here if you try to make a group of a group
where as
lightweight_template(Base : Node) class Owned : Node {
        Base getParent();
    }
}
can be Owned<Owned<Doc>>

>
> So interfaces are definitely a no-win situation for me. As far as I'm concerned interfaces are mostly useful when you need to enforce a particular set of methods onto other people who will be implementing classes that will interface with your code in a particular way. But using interfaces (in this situation) won't help ME keep my own code small, manageable, and robust.
>
> >"your object heirachy is wrong" may be a knee-jerk reaction, but you
should
> >question if your heirachy is right and why `Doc` can not have a parent (obviously there has to be a Node with a "null" parent, or no parent,
which
> >also means that it can not have any siblings too )
> >D has class invariants so Doc class must always have a null parent, all
you
> >have to do is put an assert in the "setParent method of Doc to make sure
its
> >parent can not be set, and write your code so that it can deal with
> >getParent() returning null (i.e. no parent).
> >
>
> It looks like I'll be sticking with my original strategy, throwing exceptions from the method implementations of descendant classes that shouldn't have those methods anyhow. So if you call...
>
> myComment.appendChild(myNode);
>
> ...it will throw a...
>
> DomException("You cannot call appendChild() from a Comment object");
>
> It's ugly, and I don't like it, but at least it keeps me from copying the same code into five different classes. Honestly, there's got to be a better solution to this.
as I said look at a few gui libs they all suffer from this exact problem, as
do tree classes
think about how to describe a binary tree
each node, has two nodes left or right, which can be either a parent_node or
a leaf_node;
often you want a parent_node to only no data or a small amount of data
a leaf is a node can not have children, but usually has a data item.

its not perfect but what is ... but only requires the code writing once, instead of blocking the base class defines all the possible ops, but throws an exception if the sub class does not implemtent them (realy what is required is dynamic typing, but your using a statically types lang so you have to work around the problem) if you realy can't handle static typing, use perl, self or lua!

class Node {
    Node getLeft() { throws NotValidOpException("can't do getLeft on this
type"); }
    Node getRight() { throws NotValidOpException("can't do getRight on this
type"); }
    void setLeft( Node n ) { throws NotValidOpException("can't do setLeft on
this type"); }
    void setRight( Node n ) { throws NotValidOpException("can't do setRight
on this type"); }
    int getType() { throws NotValidOpException("can't do getType on this
type"); }
    Object getValue() { throws NotValidOpException("can't do getValue on
this type"); }
}

class Parent : Node {
    Node l, r;
    Node getLeft() { return l; }
    Node getRight() { return r; }
    Node setLeft( Node n ) { l = n; }
    Node setRight( Node n ) { r = n; }
}

class Leaf : Node {
    int t; Object v;
    int getType() { return t; }
    Object getValue() { return v; }
}



« First   ‹ Prev
1 2