OOP / language design question

D

Duncan Booth

Alex said:
But why should that be? Template Method is perhaps the MOST generally
useful design pattern -- why would it be any less useful in
initialization than elsewhere?!
Because it is error prone?

Any method which is called from the constructor/initialiser has to operate
correctly on an object which at that point is not fully
constructed/initialised. So instead of having to write a method on a Foo
object, your template method has to operate on a partial Foo. The danger is
that you haven't clearly defined the partial Foo interface sufficiently and
the method tries to use other parts of the object which haven't yet been
set up. That situation gets worse when you have a class hierarchy as the
subclass needs to know that it has to do complete its own initialisation
before constructing the base class instead of afterwards, and if you are
going to document that requirement, why not do it properly and split the
construction in two?

That's why I would go for the 2-phase construction: after the first phase
you have an object which is fully initialised, just not yet
used/connected/running. For example httplib.HTTPConnection does this: you
construct the object with a host and port, but the actual connection is
triggered by a separate object.
I would suggest your example of a database connection belongs in that
category: it should have an initial unconnected idle state and a separate
connection.

I think your example of a composite window building subwindows is the sort
of use case I was asking for: it does sound tempting to construct the
window and all its subwindows together. I'm happy to concede on that one.
 
B

bruno at modulix

Duncan said:
Alex Martelli wrote:



Because it is error prone?

Programming *is* error prone.
Any method which is called from the constructor/initialiser has to operate
correctly

any method has to operate correctly anyway !-)
on an object which at that point is not fully
constructed/initialised.

In Python, when the __init__ method is called, the object is at least
fully constructed.
So instead of having to write a method on a Foo
object, your template method has to operate on a partial Foo. The danger is
that you haven't clearly defined the partial Foo interface sufficiently and
the method tries to use other parts of the object which haven't yet been
set up.

If so, the worse thing that can happen is an exception - and you'll
surely spot the problem really soon.
That situation gets worse when you have a class hierarchy as the
subclass needs to know that it has to do complete its own initialisation
before constructing the base class instead of afterwards, and if you are
going to document that requirement, why not do it properly and split the
construction in two?

It's *already* split : __new__ construct the object, __init__ initialize it.
That's why I would go for the 2-phase construction:

But that's already what you have.
after the first phase
you have an object which is fully initialised, just not yet
used/connected/running. For example httplib.HTTPConnection does this: you
construct the object with a host and port, but the actual connection is
triggered by a separate object.

If you look at file objects, they do try and open the file at init time.
Is a net or db connection that different ?

(snip)
 
C

Carl Banks

Duncan said:
Because it is error prone?

Any method which is called from the constructor/initialiser has to operate
correctly on an object which at that point is not fully
constructed/initialised. So instead of having to write a method on a Foo
object, your template method has to operate on a partial Foo. The danger is
that you haven't clearly defined the partial Foo interface sufficiently and
the method tries to use other parts of the object which haven't yet been
set up.

In Python, if you try to use an uninitialized member you get an
AttributeError; I really don't see too much inherent danger here. If
you make a mistake, the language tells you and you fix it. C++ and
Java are worse since accessing uninitialized variables is a silent
mistake, so it makes sense to avoid that kind thing in those languages.

Carl Banks
 
D

Duncan Booth

bruno said:
It's *already* split : __new__ construct the object, __init__
initialize it.


But that's already what you have.

Very good point.
If you look at file objects, they do try and open the file at init
time. Is a net or db connection that different ?

Well, yes, since the whole point is that we are discussing overriding
methods and I bet you haven't subclassed Python file objects recently.

For network or database connections you do want to supply your own
handlers for things like authentication.
 
B

bruno at modulix

Duncan said:
bruno at modulix wrote:



Very good point.




Well, yes, since the whole point is that we are discussing overriding
methods and I bet you haven't subclassed Python file objects recently.

And you win !-)

Anyway, I didn't suggest that opening a connection to whatever should be
done in the __init__ - I just wanted to point that acquiring a resource
in the initializer (and freeing it in the finalizer) can sometimes be
perfectly sensible.

wrt/ initializer as a template method, I still fail to see why this
should be a problem. The fact that one should avoid doing anything else
than initialization in the initializer is just plain old common sense
IMHO - the use of calls to other methods that can possibly be overriden
in a subclass is orthogonal. And if the guy writing the subclass do
stupid things when overridding these methods, well, too bad for him -
but as the author of the base class, that's definitively not my problem
(given proper documentation of course)

Trying to protect stupid programmers from doing stupid things is a total
waste of time anyway.
 
B

Brian van den Broek

Bruno Desthuilliers said unto the world upon 25/04/06 06:52 PM:
Duncan Booth a écrit :



Mmmm... Oh, I see. Agreed, this is not a very good example.

<snip>

This hobbyist isn't seeing Duncan's point. Wouldn't deleting the
dothis method from both classes lead to an AttributeError as
Base.__init__ calls self.dothis()?

Is the point that one could refactor out the self.dothis() from the
__init__? Or something else altogether? (I assume it can't be that
dothis isn't doing real work as it is in the context of a toy example.)

Enlightenment gratefully received.

Best to all,

Brian vdB
 
B

bruno at modulix

Brian said:
Bruno Desthuilliers said unto the world upon 25/04/06 06:52 PM:


<snip>

This hobbyist isn't seeing Duncan's point. Wouldn't deleting the dothis
method from both classes lead to an AttributeError as Base.__init__
calls self.dothis()?

Yes, of course. But Duncan (implicitely) meant "deleting the method
*and* the calls to the method".

The point is that dothis() returns a value (that is not used), and
doesn't modify the state of self.

Or at least, this what *I* understood.
Is the point that one could refactor out the self.dothis() from the
__init__? Or something else altogether? (I assume it can't be that
dothis isn't doing real work as it is in the context of a toy example.)

Seems like you are assuming too much !-)
 
L

Lawrence D'Oliveiro

Duncan Booth said:
There is a significant difference: imagine B is a base type and C a
subclass of B:

When you create an object of type C in Python, while B.__init__ is
executing self is an object of type C (albeit without all the attributes
you expect on your C).

In C++ when the B() constructor is executing the object is an object of
type B. It doesn't become a C object until the C() constructor is
executing.

In other words, the object is constructed in Python before any __init__ is
called, but in C++ it isn't constructed until after all the base class
constructors have returned.

But if "construction" is what a constructor does, then you're wrong.
 
L

Lawrence D'Oliveiro

"Carl Banks said:
You know, Python's __init__ has almost the same semantics as C++
constructors (they both initialize something that's already been
allocated in memory, and neither can return a substitute object). I
actually think constructors are misnamed in C++, they should be called
initializers (and destructors finalizers).

"Constructor" is also the term used for the corresponding method in Java.

Is there any OO language that does not use "constructor" in this sense?
I don't think there is one. This is standard OO terminology.
 
D

Duncan Booth

Lawrence said:
But if "construction" is what a constructor does, then you're wrong.
I may be wrong (my C++ is getting rusty), but my belief is that if you have
a base class B and a derived class D, then until the B() constructor has
returned, the type of the object (as indicated by RTTI or by calling
virtual methods) is a B. It isn't until after the B constructor has
returned that the object is changed into a D.

This is different from Python's behaviour where the object is created as
its final type and then initialised.
 
C

Carl Banks

Lawrence said:
"Constructor" is also the term used for the corresponding method in Java.

Is there any OO language that does not use "constructor" in this sense?
I don't think there is one. This is standard OO terminology.

Python?

Yeah, I realize it's common terminology, but I just think it's a poor
name. That Python doesn't really call __init__ a constructor is good
(I guess it doesn't really call it anything but __init__), because
constructor would be a bad name for it.


Carl Banks
 
B

bruno at modulix

Lawrence said:
"Constructor" is also the term used for the corresponding method in Java.

Is there any OO language that does not use "constructor" in this sense?

Smalltalk. Just like Python, it has constructor *and* initializer.
I don't think there is one. This is standard OO terminology.

Being "standard" doesn't imply it's accurate.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top