Antoon Pardon said:
And what about
a += b vs a.extend(b)
I can go on repeating "in the general case [these constructs] get very
different effects" just as long as you can keep proposing, as if they
might be equivalent, constructs that just aren't so in the general case.
Do I really need to point out that a.extend(b) doesn't work for tuples
and strings, while a+=b works as polymorphically as feasible on all
these types? It should be pretty obvious, I think. So, if you want to
get an AttributeError exception when 'a' is a tuple or str, a.extend(b)
is clearly the way to go -- if you want para-polymorphic behavior in
those cases, a+=b. Isn't it obvious, too?
c=a=range(3)
b=range(2)
a+=b
c
[0, 1, 2, 0, 1]
versus:
c=a=range(3)
b=range(2)
a=a+b
c
[0, 1, 2]
I wouldn't say you get different effects in *general*. You get the
same effect if you use numbers or tuples or any other immutable
object.
a+=b is defined to be: identical to a=a+b for immutable objects being
bound to name 'a'; but not necessarily so for mutable objects -- mutable
types get a chance to define __iadd__ and gain efficiency through
in-place mutation for a+=b, while the semantics of a=a+b strictly forbid
in-place mutation. *IN GENERAL*, the effects of a+=b and a=a+b may
differ, though in specific cases ('a' being immutable, or of a mutable
type which strangely chooses to define __add__ but not __iadd__) they
may be identical. Like for a+b vs b+a: in general they may differ, but
they won't differ if the types involved just happen to have commutative
addition, of if a and b are equal or identical objects, i.e., in various
special cases.
"You get different effects *in general*" does not rule out that there
may be special cases (immutable types for one issue,
commutative-addition types for another, etc, etc) in which the effects
do not differ. Indeed, if it was "always" true that you got different
effects, it would be superfluous to add that "in general" qualifier.
Therefore, I find your assertion that you "wouldn't say you get
different effects in *general*" based on finding special cases in which
the effects do not differ to be absurd and unsupportable.
That is just tradition. Suppose the "+" operator wouldn't have worked
on strings an concatenating would from the start been done by joining,
then that would have been the one obvious way to do it.
In a hypothetical language without any + operator, but with both unary
and binary - operators, the one "obvious" way to add two numbers a and b
might indeed be to code: a - (-b). So what? In a language WITH a
normal binary + operator, 'a - (-b)' is nothing like 'an obvious way'.
And what if it are three sequences of code with the same end-result,
or four. From what number isn't it a problem any more if two sequences
of that length or more produce the same result.
To add N integers that are bound to N separate identifiers, there are
(quite obviously) N factorial "sequences of [the same] length" producing
the same result. Is it "a problem"? I guess it may be considered a
minor annoyance, but it would be absurd to try and do something against
it, e.g. by arbitrary rules forbidding addition between variables except
in alphabetical order. Practicality beats purity.
I think that this goal of GvR is a bad one.
I'm sure you're a better language designer than GvR, since you're
qualified to critique, not just a specific design decision, but one of
the pillars on which he based many of the design decisions that together
made Python.
Therefore, I earnestly urge you to stop wasting your time critiquing an
inferiorly-designed language and go off and design your own, which will
no doubt be immensely superior. Good bye; don't slam the door on the
way out, please.
If someway of doing it
is usefull then I think it should be included and the fact that
it introduces more than one obvious way to do some things shouldn't
count for much.
This is exactly Perl's philosophy, of course.
Sure you shouldn't go the perl-way where things seemed to have
been introduced just for the sake of having more than obvious way
to do things. But eliminating possibilities (method chaining)
just because you don't like them and because they would create
more than one obvious way to do things, seems just as bad to
me.
If a language should not eliminate possibilities because its designer
does not like those possibilities, indeed if it's BAD for a language
designer to omit from his language the possibilities he dislikes, what
else should a language designer do then, except include every
possibility that somebody somewhere MIGHT like? And that IS a far
better description of Perl's philosophy than "just for the sake" quips
(which are essentially that -- quips).
What I have herad about the decorators is that one of the
arguments in favor of decorators is, that you have to
give the name of the function only once, where tradionally
you have to repeat the function name and this can introduce
errors.
But the same argument goes for allowing method chaining.
Without method chaining you have to repeat the name of
the object which can introduce errors.
I've heard that argument in favour of augmented assignment operators
such as += -- and there it makes sense, since the item you're operating
on has unbounded complexity... mydict[foo].bar[23].zepp += 1 may indeed
be better than repeating that horrid LHS (although "Demeter's Law"
suggests that such multi-dotted usage is a bad idea in itself, one
doesn't always structure code with proper assignment of responsibilities
to objects and so forth...).
For a plain name, particularly one which is just a local variable and
therefore you can choose to be as simple as you wish, the argument makes
no sense to me. If I need to call several operations on an object I'm
quite likely to give that object a 'temporary alias' in a local name
anyway, of course:
target = mydict[foo].bar[23].zepp
target.pop(xu1)
target.sort()
target.pop(xu3)
target.reverse()
target.pop(xu7)
Doing just the same thing when I don't need intermediate access to the
object between calls that mutate the object and currently return None is
no hardship, just as it isn't when such access IS needed. Note that you
couldn't do chaining here anyway, since pop mutates the object but also
returns a significant value...
No it isn't because programs evolve. So you may think you don't
need the result later on, but that may change, so writing it
the second way, will making changes easier later on.
Ridiculous. Keep around a+b, which for all we know here might be a
million-items list!, by having a name bound to it, without ANY current
need for that object, because some FUTURE version of your program may
have different specs?!
If specs change, refactoring the program written in the sensible way,
the way that doesn't keep memory occupied to no good purpose, won't be
any harder than refactoring the program that wastes megabytes by always
keeping all intermediate results around "just in case".
So? I sometimes get the idea that people here can't cope with
differences in how people code. So any effort must be made
to force people to code in one specific way.
When more than one person cooperates in writing a program, the group
will work much better if there is no "code ownership" -- the lack of
individualized, quirky style variations helps a lot. It's not imposible
to 'cope with differences' in coding style within a team, but it's just
one more roadblock erected to no good purpose. A language can help the
team reach reasonably uniform coding style (by trying to avoid offering
gratuitous variation which serves no real purpose), or it can hinder the
team in that same goal (by showering gratuitous variation on them).
That these implications are important is just an implication on the
design principles. If someone doesn't think particular design principles
are that important, he doesn't care that if somethings is changed that
particulat design principle will be violated. Personnaly I'm not
that impressed with the design of python, it is a very usefull language
Great, so, I repeat: go away and design your language, one that WILL
impress you with its design. Here, you're just waiting your precious
time and energy, as well of course as ours.
but having operators like '+=' which have a different kind of result
depending on whether you have a mutable or immutable object is IMO
not such a good design and I wonder what design principle inspired
them.
Practicality beats purity: needing to polymorphically concatenate two
sequences of any kind, without caring if one gets modified or not, is a
reasonably frequent need and is quite well satisfied by += for example.
Alex