This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author gregorlingl
Recipients benjamin.peterson, georg.brandl, gregorlingl, loewis
Date 2008-09-25.23:34:44
SpamBayes Score 0.0
Marked as misclassified No
Message-id <1222385688.89.0.172399497004.issue3956@psf.upfronthosting.co.za>
In-reply-to
Content
First of all I'd like to point you at a posting which I posted to
Python-dev on August 18th, where I addressed this issue in full detail. 

http://mail.python.org/pipermail/python-dev/2008-August/081846.html

I hoped to provoke a clarifying discussion but I have to complain, that
I didn't succeed with this probably because many people were on vacation
at this time.

The only substantial reply I got was by Vern Ceder, a turtle graphics
veteran who contributed a lot to the old turtle module. He wrote:

Gregor,

I don't feel authoritative on the correctness/appropriateness of the 
implementation, but I do agree completely that behavior b, 
or what you have in the 3.0 version, is vastly preferable.

Cheers,
Vern 

The design decision to use a singleton is of interest only for
interactive use. (A well designed Script uses at most one Screen() call
at the beginning. So that is no issue.)

I'll demonstrate here in a short interactive session (which you can
reproduce using IDLE with the -n switch as usual), why the solution
Martin proposes doesn't meet the requirements I tried to accomplish with
my code. This session 'simulates' a student curiously playing around and
experimenting with *the* Screen():

>>> from turtle import Screen, Turtle
>>> class YellowScreen(Screen):
	def __init__(self):
		Screen.__init__(self)
		self.bgcolor("yellow")

		
>>> s = YellowScreen()
>>> t = Turtle()
>>> for i in range(10):
	t.fd(50)
	t.lt(36)

	
>>> s1 = Screen()
>>> s1.bgcolor("pink")
>>> s = YellowScreen()
>>> s1.bgcolor()
'yellow'
>>> s1.turtles()
[<turtle.Turtle object at 0x01490450>]
>>> class TextScreen(Screen):
	def __init__(self):
		Screen.__init__(self)
		self. writer = Turtle(visible=False)
		self.writer.pu()
	def writeAt(self, x, y, txt):
		self.writer.goto(x,y)
		self.writer.write(txt)

		
>>> s = TextScreen()
>>> s.writeAt(0, -200, "Read me ...")
>>> s.turtles()
[<turtle.Turtle object at 0x01490450>, <turtle.Turtle object at 0x014902B0>]
>>> s.writer
<turtle.Turtle object at 0x014902B0>
>>> class RedScreen(Screen):
	def __init__(self):
		Screen .__init__(self)
		self.bgcolor(1, 0.5, 0.5)

		
>>> u = RedScreen()
>>> u.writeAt(0,200, "Read me too....")    # should fail!
Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    u.writeAt(0,200, "Read me too....")
AttributeError: 'RedScreen' object has no attribute 'writeAt'
>>> u = TextScreen()
>>> u.writeAt(0,200, "Read me too....")
>>> u.turtles()  # at this point for the first time occurs an 
                 # unfavorable consequence of what Martin called a
                 # 'design bug', namely a turtle in the turtles() list 
                 # which is not used any more.
[<turtle.Turtle object at 0x01490450>, <turtle.Turtle object at
0x014902B0>, <turtle.Turtle object at 0x014C2D10>]
>>> u.writer
<turtle.Turtle object at 0x014C2D10>
>>> s.writer
<turtle.Turtle object at 0x014C2D10>
    #  We want a fresh screen ...
>>> s.clear()
>>> s.turtles()
[]

So there occurres this and possibly some more somewhat weird elements, 
presumably a result of using the Singleton pattern which is especially
controversial in combination with inheritance. Nevertheless I decisively
propose to accept this behaviour in order to be able do things like the
ones demonstrated above. Morover I also consider it to be a benefit to
use spezialized and/or reusable screens derived from the Screen() class
in scripts, what would not be possible with a Screen()-function
returning *the* single _Screen() object. (All this meant in the context
of teaching and learning OOP).

Now for the additional questions of Martin:

Yes, the second if statement is superfluous. It looks like to be a
remain from Pen.__init__ from the old turtle module, where - in contrast
- it was not superfluous. My fault. It could be removed, but it doesn't
do harm. (The overwhelming part of the module is *re*written but it
still contains (in this case regrettably) quite some traces of the old
module.) And also the assignement of self to Turtle._screen in the last
line could be put into the if-statement-body. But somehow I seem to have
felt that a conditionally empty body of __init__() looks dangerous - or
at least not nice. More seriously taken, the Borg idiom ensures the
creation of new instances (with different id), sharing state and
behaviour and I somehow felt it to be better to have the last created
instance in Turtle._screen (whereas in fact this is of no importance).

My preliminary conclusion: as I'm not a professional programmer but a
teacher I can't judge the importance of observing the design 
principle mentioned by Martin. (I know the principle, I normally observe
it and consider it's non observation in the Screen class to be well
founded) But if you think, that there is no way around and it has to be
observed strictly, one had to leave everything as is and find a
better solution (with the desired behaviour) for 2.6.1. Otherwise,
having done a lot of work with the Screen class and having not
observed any unexpected behaviour (let alone crashes) when using it
I'd pragmatically still much prefer the solution which is implemented in
3.0 Even then the search for a better solution may be indicated.

Anyway I'd like to express my hope that this controversial
implementation of the last element in the class hierarchy for a very
special purpose is *not* a hint at a design bug of the entire class
hierarchy.

Regards, Gregor
History
Date User Action Args
2008-09-25 23:34:48gregorlinglsetrecipients: + gregorlingl, loewis, georg.brandl, benjamin.peterson
2008-09-25 23:34:48gregorlinglsetmessageid: <1222385688.89.0.172399497004.issue3956@psf.upfronthosting.co.za>
2008-09-25 23:34:47gregorlingllinkissue3956 messages
2008-09-25 23:34:45gregorlinglcreate