Default Value

R

Rick Johnson

Okay, you're trolling. Time for another month in the kill-file.
*plonk*

That's so typical of you. You start losing an argument, and
when you have no remaining counter arguments, you resort to
name calling. Why am i not surprised? You wanna see some
trolling?

Is this all you can conjure Steven "Sauron" D'Aprano?

.... A FEW MINDLESS ORCS?

I have defeated your orcs, and your cave trolls. I have
defeated you in my darkest hour in the keep. I have thrown
out that despot from the white city, i have even slain your
Nazgul. Heck, my little sister killed your witch king.

....AND STILL YOU THINK YOU CAN DEFEAT ME!

And now, here i stand, at the foot of the mountain of doom,
with the ring of *POWER* in my hand, and i shall cast it
into the fires from whence it came!

....WHO WILL STOP ME?

All you have remaining is your beloved "gollom van rossum"
and he has already defeated himself with his blind devotion
to this despicable ring. A ring that represents illogical
and inconsistent design philosophies. A philosophy that he
himself cannot defend.

Free my people from this plague of darkness, and cast light
on these atrocities so that the sun may bleach this language
and this community clean, and maybe we'll let you visit the
shire.

....MAYBE!
 
N

Neil Cerutti

I could cast a "virtual net" over my poor lemmings before
they jump off the cliff by throwing an exception:

Traceback (most recent screw-up last):
Line BLAH in SCRIPT
def f(x = [None, b, [a, [4]]]):
ArgumentError: No mutable default arguments allowed!

So tell me, oh Great and Powerful Wizard of Rick, how is the
interpreter supposed to know which defaults are mutable? I
mean, it's obviously some intrinsic property of the object.
Somehow one thing is clearly immutable, another thing clearly
isn't. Will there be a PyObject_IsImmutable() API?

Oh! I know. Function argument defaults will now be restricted
to int/float/tuple. That would do it, right? Nobody would be
bothered by little restrictions like that, would they.

I've been around here long enough to have even participated in
one of these discussions before.

Rick, it's not a wart, It's a gotcha.

The reason it's a gotcha is this: In order to predict what will
happen correctly, you have to have mastered three separate Python
concepts.

1. How name-binding works.
2. How argument passing works, i.e., via name-binding.
3. When default arguments are evaluated.
4. The Python object model.

OK, you have to know four things. Curses! I'll come in again.
 
M

MRAB

It isn't clear to me from your posts what exactly you're
proposing as an alternative to the way Python's default
argument binding works. In your version of Python, what
exactly would happen when I passed a mutable argument as a
default value in a def statement? E.g. this:
a = [1, 2, 3]
a.append(a)
b = object()
def f(x = [None, b, [a, [4]]]):
... pass # do something

What would you like to see the interpreter do in this case?

Ignoring that this is a completely contrived example that has
no use in the real world, here are one of three methods by
which i can handle this:

============================================================
The Benevolent Approach:
============================================================
I could cast a "virtual net" over my poor lemmings before
they jump off the cliff by throwing an exception:

Traceback (most recent screw-up last):
Line BLAH in SCRIPT
def f(x = [None, b, [a, [4]]]):
ArgumentError: No mutable default arguments allowed!
What about this:

def f(x=Foo()):
pass # do something

Should it raise an exception? Only if a Foo instance is mutable? How do
you know whether such an instance is mutable?
============================================================
The Apathetic Approach:
============================================================
I could just assume that a programmer is responsible for the
code he writes. If he passes mutables into a function as
default arguments, and then mutates the mutable later, too
bad, he'll understand the value of writing solid code after
a few trips to exception Hell.

============================================================
The Malevolent Approach (disguised as beneva-loon-icy):
============================================================
I could use early binding to confuse the hell out of him and
enjoy the laughs with all my ivory tower buddies as he falls
into fits of confusion and rage. Then enjoy again when he
reads the docs. Ahh, the gift that just keeps on giving!
How does the "Apathetic Approach" differ from the "Malevolent Approach"?
============================================================
Conclusion:
============================================================
As you can probably guess the malevolent approach has some
nice fringe benefits.

You know, out of all these post, not one of you guys has
presented a valid use-case that will give validity to the
existence of this PyWart -- at least not one that CANNOT be
reproduced by using my fine examples. All you can muster is
some weak argument about protecting the lemmings.

Is anyone up the challenge?
Does anyone here have any real chops?

PS: I won't be holding my breath.
Speaking of which, on 11 January 2013, in the thread "PyWart: Import
resolution order", you were asked:

"""Got any demonstrable code for Python 4000 yet?"""

and you said:

"""I am working on it. Stay tuned. Rick is going to rock your little
programming world /very/ soon."""

How soon is "/very/ soon" (clearly longer than 5 months), and how did
you fix this "PyWart"?
 
R

Rick Johnson

Steven, you wouldn't know "trolling" even if you were an honorary salad tosser at a troll face-sitting contest.
 
R

Rick Johnson

Rick, it's not a wart, It's a gotcha. The reason it's a
gotcha is this: In order to predict what will happen
correctly, you have to have mastered three separate Python
concepts.

1. How name-binding works.
2. How argument passing works, i.e., via name-binding.
3. When default arguments are evaluated.
4. The Python object model.

I understand all these concepts in a Python context quite
well, but understanding a PyWart is no validation for it's
continued existence.

You probably understand the common cold quite well. If you
do you'll wash your hands before eating, and avoid exposure
to sick people.

THAT'S CALLED A WORKAROUND!

But disease is not yet fully under human control, we are
forced to used the workaround. Whereas, languages are. So
designing a language poorly and then getting upset because
people don't praise your clunky work-around is ludicrous.

Psst: THE PROBLEM IS SELF-INDUCED!

Mankind, the only creature dumb enough to self-induce his
own hardships -- somewhere a higher intelligence must be
laughing... or crying, who knows. *sigh*
 
R

Rick Johnson

How does the "Apathetic Approach" differ from the
"Malevolent Approach"?

In the apathetic approach i allow the programmer to be the
sole proprietor of his own misfortunes. He lives by the
sword, and thus, he can die by the sword.

Alternatively the malevolent approach injects misfortunes
for the programmer on the behalf of esoteric rules. In this
case he will live by sword, and he could die by the sword,
or he could be unexpectedly blown to pieces by a supersonic
Howitzer shell.

It's an Explicit death versus an Implicit death; and Explicit
should ALWAYS win!

The only way to strike a reasonable balance between the
explicit death and implicit death is to throw up a warning:

"INCOMING!!!!"

Which in Python would be the "MutableArgumentWarning".

*school-bell*
 
M

MRAB

In the apathetic approach i allow the programmer to be the
sole proprietor of his own misfortunes. He lives by the
sword, and thus, he can die by the sword.

Alternatively the malevolent approach injects misfortunes
for the programmer on the behalf of esoteric rules. In this
case he will live by sword, and he could die by the sword,
or he could be unexpectedly blown to pieces by a supersonic
Howitzer shell.

It's an Explicit death versus an Implicit death; and Explicit
should ALWAYS win!

The only way to strike a reasonable balance between the
explicit death and implicit death is to throw up a warning:

"INCOMING!!!!"

Which in Python would be the "MutableArgumentWarning".

*school-bell*
I notice that you've omitted any mention of how you'd know that the
argument was mutable.
 
R

Rotwang

It isn't clear to me from your posts what exactly you're
proposing as an alternative to the way Python's default
argument binding works. In your version of Python, what
exactly would happen when I passed a mutable argument as a
default value in a def statement? E.g. this:
a = [1, 2, 3]
a.append(a)
b = object()
def f(x = [None, b, [a, [4]]]):
... pass # do something

What would you like to see the interpreter do in this case?

Ignoring that this is a completely contrived example that has
no use in the real world, here are one of three methods by
which i can handle this:

I didn't ask what alternative methods of handling default argument
binding exist (I can think of several, but none of them strikes me as
preferable to how Python currently does it). I asked what would happen
in /your/ version of Python. Which of the alternatives that you present
would have been implemented, if you had designed the language?

============================================================
The Benevolent Approach:
============================================================
I could cast a "virtual net" over my poor lemmings before
they jump off the cliff by throwing an exception:

Traceback (most recent screw-up last):
Line BLAH in SCRIPT
def f(x = [None, b, [a, [4]]]):
ArgumentError: No mutable default arguments allowed!

So how does the interpreter know whether an arbitrary object passed as a
default value is mutable or not?
Let's imagine for a second if Python allowed mutable keys in
a dictionary,

which it does
would you be surprised if you used a mutable
for a key, then you mutated the mutable key, then you could
not access the value from the original key?

## Imaginary code ##
py> lst = [3]
py> d = {1:2, lst:4}
py> lst.append(10)
py> d[lst]
opps, KeyError!

Would you REALLY be so surprised? I would not. But more
importantly, does Python need to protect you from being such
an idiot? I don't think so!

Now, I don't really believe that you think that the user shouldn't be
protected from doing one idiotic thing with mutable dict keys but should
be protected from doing another idiotic thing with mutable default
arguments, especially as you've already been given a use case for the
latter. So I assume that The Benevolent Approach is not the approach you
would have gone for if you had designed the language, right? If so then
let's ignore it.

============================================================
The Apathetic Approach:
============================================================
I could just assume that a programmer is responsible for the
code he writes. If he passes mutables into a function as
default arguments, and then mutates the mutable later, too
bad, he'll understand the value of writing solid code after
a few trips to exception Hell.

It seems to me that this is exactly what currently happens.

============================================================
The Malevolent Approach (disguised as beneva-loon-icy):
============================================================
I could use early binding to confuse the hell out of him and
enjoy the laughs with all my ivory tower buddies as he falls
into fits of confusion and rage. Then enjoy again when he
reads the docs. Ahh, the gift that just keeps on giving!

My question was about how you think the language should work, not about
what your buddies should or shouldn't enjoy. In terms of how a language
actually works, is there any difference between The Malevolent Approach
and The Apathetic Approach? And is there any difference between either
of them and what Python currently does?

============================================================
Conclusion:
============================================================
As you can probably guess the malevolent approach has some
nice fringe benefits.

You know, out of all these post, not one of you guys has
presented a valid use-case that will give validity to the
existence of this PyWart -- at least not one that CANNOT be
reproduced by using my fine examples.

Of course using a mutable default as a cache can be reproduced by other
means, as can another common use case that I don't think anyone's
mentioned yet (defining functions parametrised by variables whose values
aren't known until runtime). That's hardly an argument against it - you
might as well argue that Python shouldn't have decorators, or that it
shouldn't have for loops because their behaviour can be reproduced with
while loops.

But this is beside the point anyway, until you present an alternative to
Python's current behaviour. If you do so then we can start debating the
relative merits of the two approaches.
 
R

Rick Johnson

I notice that you've omitted any mention of how you'd know that the
argument was mutable.

My argument has always been that mutables should not be
passed into subroutines as default arguments because bad
things can happen. And Python's excuse of saving the poor
dummies is no excuse.

It does not matter if we are passing the arguments into the
current implementation of "python functions which maintain
state of default mutables arguments between successive
calls" or in a more desirable system of truly "stateless
subroutines".

I also believe that a programmer should not be prevented
from passing mutable default arguments, but if he does, I'm
not going to provide any sort of protection -- other than
possibly throwing up a warning message.

Now, YOU, and everyone else, cannot destroy the main points
of my argument because the points are in fact rock solid,
however, what you will do is to focus in one small detail,
one little tiny (perceived) weakness in the armor, and you
will proceed to destroy that small detail (in this case how
i will determine mutability), and hope that the destruction
of this insignificant detail will start a chain-reaction
that will propagate out and bring down my entire position.

So you want me to tell you how to query the mutability of an
object... Ha Ha Ha! Sorry, but that's not going to happen!

Why should i help the developers of this language. What have
they done for me? Hmm, let's see. They called me names.
Trolled up my posts. Written me off. Refused to answer my
questions. Been absolutely rude. etc, etc... Banned me from
lists i've never posted on and then proclaim the list is
free and open to all... BS!

WOULD YOU OFFER ASSISTANCE TO PEOPLE THAT HAVE TREATED YOU THIS WAY?

And let's just be honest. You don't want my assistance. You
just want me to fumble the ball. Then you can use that
fumble as an excuse to write me off. Nice try!

You want to gain my respect? Then start engaging in honest
debates. Start admitting that yes, somethings about Python
are not only undesirable, they're just plain wrong.

Stop calling me a troll when i am not. And not just me, stop
calling other people trolls too! Stop using the personal
attacks and straw man arguments.

Finally, get the core devs to realize that this list matters
and they need to participate (including you know who!)
 
S

Steven D'Aprano

On 21/06/2013 21:44, Rick Johnson wrote: [...]
Which in Python would be the "MutableArgumentWarning".

*school-bell*
I notice that you've omitted any mention of how you'd know that the
argument was mutable.

That's easy. Just call ismutable(arg). The implementation of ismutable is
just an implementation detail, somebody else can work that out. A
language designer of the sheer genius of Rick can hardly be expected to
worry himself about such trivial details.
 
R

Rick Johnson

On 21/06/2013 19:26, Rick Johnson wrote:
[...]
I didn't ask what alternative methods of handling default
argument binding exist (I can think of several, but none
of them strikes me as preferable to how Python currently
does it). I asked what would happen in /your/ version of
Python. Which of the alternatives that you present would
have been implemented, if you had designed the language?

The apathetic approach. However, you fail to understand that
whilst Python's current implementation is partly apathetic,
is is also benevolent, and malevolent simultaneously. My
approach is purely apathetic. I'll explain later. Stay
tuned.
[...]
So how does the interpreter know whether an arbitrary
object passed as a default value is mutable or not? Not
that it really matters.

Well i'm glad it does not matter to you because it does not
matter to me either. *shrugs*
which it does

Am i just to take your word for this? You cannot provide an
example? Here, allow me to "break the ice":

# Literal
py> d = {[1]:2}
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
d = {[1]:2}
TypeError: unhashable type: 'list'
# Symbol
py> lst = [1]
py> d = {lst:2}
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
d = {lst:2}
TypeError: unhashable type: 'list'

Hmm, maybe only certain mutables work? Great, more esoteric
rules! Feel free to enlighten me since i'm not going to
waste one second of my time pursuing the docs just to learn
about ANOTHER unintuitive PyWart i have no use for.
Now, I don't really believe that you think that the user
shouldn't be protected from doing one idiotic thing with
mutable dict keys but should be protected from doing
another idiotic thing with mutable default arguments,
especially as you've already been given a use case for the
latter. So I assume that The Benevolent Approach is not
the approach you would have gone for if you had designed
the language, right? If so then let's ignore it.

You are correct. Finally, we can agree on something.
It seems to me that this is exactly what currently happens.

(is this lazy readers day? I swear i explained this earlier)

And here is where you are wrong. In the current implementation
python functions carry the state of mutable default arguments
between successive calls. That's a flaw. Observe:

py> def foo(arg=[]):
... arg.append(1)
... print(arg)
...
py> foo()
[1]
py> foo()
[1, 1]
py> foo()
[1, 1, 1]

No, no, NO! That's wrong! Subroutines should be stateless.
That means that an empty mutable default argument will
ALWAYS be empty at each call of the subroutine. This is
what should happen:

py> def foo(arg=[]):
... arg.append(1)
... print(arg)
...
py> foo()
[1]
py> foo()
[1]
py> foo()
[1]

Yes, Yes, YES! That is intuitive! That is sane! Now, what if
we pass a reference to a mutable object? What then. Well, let's
see:

py> lst = range(5)
py> lst
[0, 1, 2, 3, 4]
py> def foo(arg=lst):
... arg.append(1)
... print(arg)
...
py> foo()
[0, 1, 2, 3, 4, 1]
py> foo()
[0, 1, 2, 3, 4, 1, 1]

That's fine. Because the object was already created OUTSIDE
the subroutine. So therefore, modifications to the mutable
are not breaking the fundamental of statelessness INSIDE
subroutines. The modification is merely a side effect, and
the subroutine is unconcerned with anything that exists
beyond it's own scope.

IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?
My question was about how you think the language should
work, not about what your buddies should or shouldn't
enjoy.

My buddies? This design flaw is NOT my brain child. Your
barking up the wrong tree pal.
In terms of how a language actually works, is there
any difference between The Malevolent Approach and The
Apathetic Approach? And is there any difference between
either of them and what Python currently does?

I explained this to MRAB already.
Of course using a mutable default as a cache can be
reproduced by other means, as can another common use case
that I don't think anyone's mentioned yet (defining
functions parametrised by variables whose values aren't
known until runtime). That's hardly an argument against it
- you might as well argue that Python shouldn't have
decorators, or that it shouldn't have for loops because
their behaviour can be reproduced with while loops.

Nice attempt at sleight of hand but your logic is clumsy.

Your trying to argue that my use of a "custom callable state
object" (to avoid the esoteric and unintuitive nature of the
current implementation of Python "mutable function
arguments") is somehow only a mere reproduction of the
function behavior and has no positive benefits, when in
fact, it has a HUGE direct benefit:

* AVOIDING A FLAW IN THE LANGUAGE

It also has quite a few positive side effects:

* CODE ENCAPSULATION
* INTERFACE
* USING THE CORRECT TOOL FOR THE JOB++
* READABILITY
* NO HIDDEN SURPRISES
* LESS BUGGY

How much more justification do you need?
or that it shouldn't have for loops because their
behaviour can be reproduced with while loops.

Yes, iterating a sequence can be achieved using a "while
loop", but "for loops" should not be thrown out because they
offer a specific type of iteration that nicely complements a
while loop. Plus, for loops do not have any strange side
effects (unlike Python functions). They do one thing and
they do damn well! So stop picking on for loops :)

I want Python functions to also "do one thing and do it
well", and what is that "one thing" you ask, execute
subprograms.
But this is beside the point anyway, until you present an
alternative to Python's current behavior. If you do so
then we can start debating the relative merits of the two
approaches.

The fix is simple. No more "magical Python functions", only
stateless routines. I've explained this ad nauseam already,
and until you provide more specific questions on the matter,
i refuse to reply to any more bombastically general questions.
 
I

Ian Kelly

On 21/06/2013 21:44, Rick Johnson wrote: [...]
Which in Python would be the "MutableArgumentWarning".

*school-bell*
I notice that you've omitted any mention of how you'd know that the
argument was mutable.

That's easy. Just call ismutable(arg). The implementation of ismutable is
just an implementation detail, somebody else can work that out. A
language designer of the sheer genius of Rick can hardly be expected to
worry himself about such trivial details.

While we're at it, I would like to petition for a function
terminates(f, args) that I can use to determine whether a function
will terminate before I actually call it.
 
S

Steven D'Aprano

Oh! I know. Function argument defaults will now be restricted to
int/float/tuple. That would do it, right? Nobody would be bothered by
little restrictions like that, would they.

Alas, tuples won't do it. Fortunately, you can include str and bytes
(unicode and str) and frozenset in the "Good List". Tuples have to go
into the "Bad List" because, although they themselves are immutable,
their contents may not be. Imagine the confusion and horror that poor
developers will experience when they do something like this:

def func(arg, extra=(23, 'foo', [])):
[code goes here...]
extra[2].append("something")
[more code...]


and they've now mutated the immutable default!

Thinking about this, I think that the only safe thing to do in Rickython
4000 is to prohibit putting mutable objects inside tuples. Putting a list
or a dict inside a tuple is just a bug waiting to happen!
 
C

Chris Angelico

# Literal
py> d = {[1]:2}
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
d = {[1]:2}
TypeError: unhashable type: 'list'
# Symbol
py> lst = [1]
py> d = {lst:2}
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
d = {lst:2}
TypeError: unhashable type: 'list'

Hmm, maybe only certain mutables work? Great, more esoteric
rules! Feel free to enlighten me since i'm not going to
waste one second of my time pursuing the docs just to learn
about ANOTHER unintuitive PyWart i have no use for.
def __hash__(self):
return 42
a=HashableList()
a []
a.append(1)
a.append(2)
a.append(3)
a [1, 2, 3]
d={a:123}
d {[1, 2, 3]: 123}
a.append(4)
d[a]
123

It's nothing to do with mutability, all to do with hashability. And
you can pick a number of different ways of hashing these objects, like
going for the object's id(), or attempting to hash tuple(self) and
falling back on id(), or anything you like. Easy.

ChrisA
 
I

Ian Kelly

which it does

Am i just to take your word for this? You cannot provide an
example? Here, allow me to "break the ice":

# Literal
py> d = {[1]:2}
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
d = {[1]:2}
TypeError: unhashable type: 'list'
# Symbol
py> lst = [1]
py> d = {lst:2}
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
d = {lst:2}
TypeError: unhashable type: 'list'

Hmm, maybe only certain mutables work? Great, more esoteric
rules! Feel free to enlighten me since i'm not going to
waste one second of my time pursuing the docs just to learn
about ANOTHER unintuitive PyWart i have no use for.

The answer to this conundrum is staring you in the face. Note that
the TypeError complains that you passed it an "unhashable" type, and
not that you passed it a "mutable" type. If you want to take a
mutable type and make it hashable, just add a __hash__ method.

class HashableList(list):
def __hash__(self):
return 42
d = dict()
hl = HashableList(range(5))
hl2 = HashableList(range(6, 10))
d[hl] = 10
d[hl2] = 20
d
{[0, 1, 2, 3, 4]: 10, [6, 7, 8, 9]: 20}

Additionally, instances of user-defined classes are, by default, both
mutable and hashable. This is safe because equality and hashing for
such objects are by default based on identity. If you override the
__eq__ method though, then you lose hashability unless you explicitly
override __hash__ as well.
Now, I don't really believe that you think that the user
shouldn't be protected from doing one idiotic thing with
mutable dict keys but should be protected from doing
another idiotic thing with mutable default arguments,
especially as you've already been given a use case for the
latter. So I assume that The Benevolent Approach is not
the approach you would have gone for if you had designed
the language, right? If so then let's ignore it.

You are correct. Finally, we can agree on something.
It seems to me that this is exactly what currently happens.

(is this lazy readers day? I swear i explained this earlier)

And here is where you are wrong. In the current implementation
python functions carry the state of mutable default arguments
between successive calls. That's a flaw. Observe:

py> def foo(arg=[]):
... arg.append(1)
... print(arg)
...
py> foo()
[1]
py> foo()
[1, 1]
py> foo()
[1, 1, 1]

No, no, NO! That's wrong! Subroutines should be stateless.
That means that an empty mutable default argument will
ALWAYS be empty at each call of the subroutine. This is
what should happen:

py> def foo(arg=[]):
... arg.append(1)
... print(arg)
...
py> foo()
[1]
py> foo()
[1]
py> foo()
[1]

Yes, Yes, YES! That is intuitive! That is sane! Now, what if
we pass a reference to a mutable object? What then. Well, let's
see:

py> lst = range(5)
py> lst
[0, 1, 2, 3, 4]
py> def foo(arg=lst):
... arg.append(1)
... print(arg)
...
py> foo()
[0, 1, 2, 3, 4, 1]
py> foo()
[0, 1, 2, 3, 4, 1, 1]

That's fine. Because the object was already created OUTSIDE
the subroutine. So therefore, modifications to the mutable
are not breaking the fundamental of statelessness INSIDE
subroutines. The modification is merely a side effect, and
the subroutine is unconcerned with anything that exists
beyond it's own scope.

IS ALL THIS REGISTERING YET? DO YOU UNDERSTAND?
My question was about how you think the language should
work, not about what your buddies should or shouldn't
enjoy.

My buddies? This design flaw is NOT my brain child. Your
barking up the wrong tree pal.
In terms of how a language actually works, is there
any difference between The Malevolent Approach and The
Apathetic Approach? And is there any difference between
either of them and what Python currently does?

I explained this to MRAB already.
Of course using a mutable default as a cache can be
reproduced by other means, as can another common use case
that I don't think anyone's mentioned yet (defining
functions parametrised by variables whose values aren't
known until runtime). That's hardly an argument against it
- you might as well argue that Python shouldn't have
decorators, or that it shouldn't have for loops because
their behaviour can be reproduced with while loops.

Nice attempt at sleight of hand but your logic is clumsy.

Your trying to argue that my use of a "custom callable state
object" (to avoid the esoteric and unintuitive nature of the
current implementation of Python "mutable function
arguments") is somehow only a mere reproduction of the
function behavior and has no positive benefits, when in
fact, it has a HUGE direct benefit:

* AVOIDING A FLAW IN THE LANGUAGE

It also has quite a few positive side effects:

* CODE ENCAPSULATION
* INTERFACE
* USING THE CORRECT TOOL FOR THE JOB++
* READABILITY
* NO HIDDEN SURPRISES
* LESS BUGGY

How much more justification do you need?
or that it shouldn't have for loops because their
behaviour can be reproduced with while loops.

Yes, iterating a sequence can be achieved using a "while
loop", but "for loops" should not be thrown out because they
offer a specific type of iteration that nicely complements a
while loop. Plus, for loops do not have any strange side
effects (unlike Python functions). They do one thing and
they do damn well! So stop picking on for loops :)

I want Python functions to also "do one thing and do it
well", and what is that "one thing" you ask, execute
subprograms.
But this is beside the point anyway, until you present an
alternative to Python's current behavior. If you do so
then we can start debating the relative merits of the two
approaches.

The fix is simple. No more "magical Python functions", only
stateless routines. I've explained this ad nauseam already,
and until you provide more specific questions on the matter,
i refuse to reply to any more bombastically general questions.
 
C

Chris Angelico

Thinking about this, I think that the only safe thing to do in Rickython
4000 is to prohibit putting mutable objects inside tuples. Putting a list
or a dict inside a tuple is just a bug waiting to happen!

I think you're onto something here, but you really haven't gone far
enough. Mutable objects *anywhere* are a problem. The solution?
Abolish mutable objects. Strings (bytes and Unicode), integers,
decimals (floats are a problem to many people), tuples of the above,
and dictionaries mapping any of the above to any other of the above,
should be enough to do everything.

ChrisA
 
C

Chris Angelico

On 21/06/2013 21:44, Rick Johnson wrote: [...]
Which in Python would be the "MutableArgumentWarning".

*school-bell*

I notice that you've omitted any mention of how you'd know that the
argument was mutable.

That's easy. Just call ismutable(arg). The implementation of ismutable is
just an implementation detail, somebody else can work that out. A
language designer of the sheer genius of Rick can hardly be expected to
worry himself about such trivial details.

While we're at it, I would like to petition for a function
terminates(f, args) that I can use to determine whether a function
will terminate before I actually call it.

Nice idea from a theoretical point of view, but practicality beats
purity, and most people know their functions will terminate (that's
what Ctrl-C is for). No, I want a function isbuggy(f) to find out
whether a function is, well, buggy. We could abolish all unit-testing
if we had that.

ChrisA
 
R

Rick Johnson

Tuples have to go into the "Bad List" because, although
they themselves are immutable, their contents may not be.
Imagine the confusion and horror that poor developers will
experience when they do something like this:

def func(arg, extra=(23, 'foo', [])):
[code goes here...]
extra[2].append("something")
[more code...]

and they've now mutated the immutable default! Thinking
about this, I think that the only safe thing to do in
Rickython 4000 is to prohibit putting mutable objects
inside tuples. Putting a list or a dict inside a tuple is
just a bug waiting to happen!

Geezsus, the warts in this language are innumerable!

So what your saying is that Python Tuples are "immutable"
like automobiles passengers are "immutable". Sure you can
design the car for a maximum number of passengers, but as
soon as the circus clowns show up, all bets are off!

This whole language is a joke! It just some sick joke! ROTF
 
M

MRAB

My argument has always been that mutables should not be
passed into subroutines as default arguments because bad
things can happen. And Python's excuse of saving the poor
dummies is no excuse.

It does not matter if we are passing the arguments into the
current implementation of "python functions which maintain
state of default mutables arguments between successive
calls" or in a more desirable system of truly "stateless
subroutines".

I also believe that a programmer should not be prevented
from passing mutable default arguments, but if he does, I'm
not going to provide any sort of protection -- other than
possibly throwing up a warning message.
So, having mutables as default arguments is a bad idea, but a
programmer should not be prevented from doing that, and a warning
message should be printed on such occasions.
Now, YOU, and everyone else, cannot destroy the main points
of my argument because the points are in fact rock solid,
however, what you will do is to focus in one small detail,
one little tiny (perceived) weakness in the armor, and you
will proceed to destroy that small detail (in this case how
i will determine mutability), and hope that the destruction
of this insignificant detail will start a chain-reaction
that will propagate out and bring down my entire position.
In order to print a warning, Python needs to know whether the object is
mutable, so it's an important detail.
So you want me to tell you how to query the mutability of an
object... Ha Ha Ha! Sorry, but that's not going to happen!
It's a detail that you're not going to help to solve.
Why should i help the developers of this language. What have
they done for me?
They've developed this language, and provided it for free. They've even
released the source code.

You perceive flaws that you say must be fixed, but you're not going to
help to fix them.
WOULD YOU OFFER ASSISTANCE TO PEOPLE THAT HAVE TREATED YOU THIS WAY?

And let's just be honest. You don't want my assistance. You
just want me to fumble the ball. Then you can use that
fumble as an excuse to write me off. Nice try!
I _do_ want you to help to improve the language, and I don't care if
you don't get it right first time. I didn't get it right first time
when I worked on the regex module (I think that what I have on PyPI is
my _third_ attempt!).
You want to gain my respect? Then start engaging in honest
debates. Start admitting that yes, somethings about Python
are not only undesirable, they're just plain wrong.
Python isn't perfect, but then no language is perfect. There will
always be compromises, and the need to maintain backwards compatibility
means that we're stuck with some "mis-features", but I think it's still
worth using; I still much prefer it to other languages.
Stop calling me a troll when i am not. And not just me, stop
calling other people trolls too! Stop using the personal
attacks and straw man arguments.
???

Finally, get the core devs to realize that this list matters
and they need to participate (including you know who!)
Everyone is a volunteer. The core devs contribute by developing the
language, and whether they participate in this particular list is
entirely up to them; how they choose to spend _their own_ free time is,
again, entirely up to them.
 

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

Forum statistics

Threads
473,772
Messages
2,569,588
Members
45,100
Latest member
MelodeeFaj
Top