Pythonification of the asterisk-based collection packing/unpacking syntax

S

Steven D'Aprano

I do have one more thing to point out, which is that currently the
Python vararg syntax is very difficult to Google for.

You're coming in late to the conversation, but that was literally the
second thing pointed out by the original poster:

Throwing an idea for a PEP out there:

It strikes me that the def func(*args, **kwargs) syntax is rather
unpytonic. It certainly did not have that 'for line in file'
pythonic obviousness for me as a beginner. Plus, asterikses are
impossible to google for, so finding out what exactly they do more
or less forces you to write a forum post about it.

And rebutted. Modesty[1] prevents me from quoting myself, but here are
some links to searches:

http://duckduckgo.com/?q=python+asterisk
http://duckduckgo.com/?q=python+*

My normal first place to look for something is Wikipedia. Enjoy it before
SOPA kills it.

http://en.wikipedia.org/wiki/Asterisk#Programming_languages


In the first pages
of the four searches matching "python (function)? (star | asterisk)",

Your search looks overly complicated to me.

I'm not an expert on Google's syntax, but if you search for "python,
optionally with function", isn't that the same as just searching for
"python" since it will return hits either with or without "function"?

I certainly remember having a small amount of difficulty figuring out
what the heck * and ** did the first time I encountered them.

Answering that sort of question is what the interactive interpreter
excels at. Suppose you see a function declared with *args as an argument,
and you have no idea what it means. Try it and find out!

py> def spam(*args):
.... print(args, type(args))
....
py> spam(42)
((42,), <type 'tuple'>)
py> spam(42, 23)
((42, 23), <type 'tuple'>)

Never underestimate the power of Python's introspection tools, especially
the two simplest ones: print and type. Often you will learn more in 10
minutes experimentation than in an hour googling.



[1] Eh, who am I fooling?
 
S

Steven D'Aprano

This would suggest perhaps some keywords might be called for instead of
operators.

The barrier to new keywords in Python is very high. Not going to happen
for something that already has perfectly good syntax already familiar to
Python and Ruby programmers. Might else well try to get C and Java to
stop using "..." (ellipses).

In the grand scheme of things the argument packing and
unpacking are not *all* that common, so I don't think the syntactic
burden would be immense.

The burden is that you complicate the compiler and reduce the pool of
useful names available to the programmer. To be useful, the keywords need
to be short, meaningful and memorable -- which means they're already used
in code, which you will break needlessly.

With operators that otherwise would be illegal, the programmer doesn't
need to learn about varargs until they need to. With keywords, the
programmer needs to learn "you can't use varargs or kwargs as variable
names" practically from day 1.

But then you could also say
def foo(varargs(list) l, kwargs(dict) d)

So you're not just adding keywords, you're adding new syntax: something
which looks like a function call, but isn't a function call. Another
feature which the programmer has to learn just to be able to read Python
source code -- and one which almost certainly is going to clash with
function annotations as people start using them.

I'm going to pose the same question to you I have already posed to Eelco:
in your proposal, what happens if the caller has shadowed the list built-
in? Does argument l become a built-in list, or does it become whatever
type list is currently bound to?

Some more questions:

Can varargs accepted arbitrary callables, or only a fixed set of known
types?

How does this differ from what can be done with annotations?
 
C

Chris Angelico

My normal first place to look for something is Wikipedia. Enjoy it before
SOPA kills it.

http://en.wikipedia.org/wiki/Asterisk#Programming_languages

I would never expect to find this sort of thing in the article on the
asterisk; maybe I'd look on the language's article, but more likely I
would be looking for info on the language's own web site.
Your search looks overly complicated to me.

I understand this to mean that he did four searches:
* python star
* python function star
* python asterisk
* python function asterisk
Never underestimate the power of Python's introspection tools, especially
the two simplest ones: print and type. Often you will learn more in 10
minutes experimentation than in an hour googling.

+1 QOTW. I refer to this as "IIDPIO debugging" (Eyed Pio) - If In
Doubt, Print It Out.

ChrisA
 
S

Steven D'Aprano

Something like ML or Haskell, which does not even allow integer to
double promotions, is very strong typing. Something like Java, which
allows some arithmetic conversion and also automatic stringification (a
la "1" + 1) is somewhere in the middle of the spectrum. Personally I'd
put Python even weaker on account of things such as '[1,2]*2' and '1 <
True' being allowed,

They are not examples of weak typing. The first is an example of operator
overloading, the second is a side-effect of a compromise made for
backwards compatibility.

If the first example were written:

[1, 2].repeat(2)

I expect you'd be perfectly happy with it as an unexceptional example of
a list method: it takes an integer count, and returns a new list
consisting of the elements of the original list repeated twice.

If it were written:

[1, 2].__mul__(2)

you'd probably raise an eyebrow at the ugliness of the method name, but
you would be okay with the concept.

Well, that's exactly what it is in Python: the list __mul__ method
performs sequence multiplication (repeating the contents), which
overloads the * operator. No automatic type conversions needed, so not an
example of weak typing.


As for comparisons between ints and True or False, that's not weak typing
either, because True and False *are* ints: bool is a subclass of int.
This was done purely for historical reasons: originally Python didn't
have a bool type, and you used 0 and 1 by convention for boolean values.
When it was decided to add a bool type, the least disruptive way to do
this was to define it as a subclass of int.
 
R

Roy Smith

Never underestimate the power of Python's introspection tools, especially
the two simplest ones: print and type. Often you will learn more in 10
minutes experimentation than in an hour googling.

+1 QOTW. I refer to this as "IIDPIO debugging" (Eyed Pio) - If In
Doubt, Print It Out.[/QUOTE]

I always knew it by the name "Ask the computer". As in, "WTF is foo?
Let's ask the computer!".

In addition to print and type, I'm a big fan of dir(). Often, I know an
object has a method to do what I want, but I can't remember the name.
For example, the other day, I was using a set (which I don't use very
often). I needed the method to remove an item from the set. Faster
than finding the right place in the docs, I just fired up an interpreter
and typed dir(set()) at it.
 
C

Chris Angelico

In addition to print and type, I'm a big fan of dir().  Often, I know an
object has a method to do what I want, but I can't remember the name.
For example, the other day, I was using a set (which I don't use very
often).  I needed the method to remove an item from the set.  Faster
than finding the right place in the docs, I just fired up an interpreter
and typed dir(set()) at it.

That's excellent when all you need is the name. I usually have IDLE
running (all the time - which sometimes produces oddities after I
experiment with monkey-patching some module or other, and then oddly
enough, things don't work properly!!), and will snap off "help(foo)"
for any foo. Unfortunately help() is at times unhelpful, and even at
its best it's very spammy. There's no one best solution; the
successful programmer will usually have a large toolset at his
disposal.

ChrisA
 
E

Eelco

"Type constraint" normally refers to type restrictions on *input*: it is
a restriction on what types are accepted. When it refers to output, it is
not normally a restriction, therefore "constraint" is inappropriate.
Instead it is normally described as a coercion, cast or conversion.
Automatic type conversions are the opposite of a constraint: it is a
loosening of restrictions. "I don't have to use a list, I can use any
sequence or iterator".

Casts or conversions are a runtime concept; im talking about
declarations. That seems to be the source of your confusion.
In iterator unpacking, it is the *output* which is a list, not a
restriction on input: in the statement:

head, *tail = sequence

tail may not exist before the assignment, and so describing this as a
constraint on the type of tail is completely inappropriate.

Yes, the variable tail is being (re)declared here. Thats exactly why I
call it a type constraint. Im not sure what the CS books have to say
on the matter, I guess this use of the term entered my lexicon through
the C# developer team. Either way, you seem to be the only one who
does not grok my intended meaning, so I suggest you try reading it
again.
We don't demand anything, any more than when we say:

for x in range(1, 100):

we "demand" that x is not just any python object, but rather an int.

Rather, we accept what we're given: in case of range and the for loop, we
are given an int. In the case of extended tuple unpacking, we are given a
list.

for x in range is syntactic sugar for a series of assignments to x; x
is an unconstrained variable that will indeed take anything it gets;
the semantics of what comes after 'x' does in no way depend on x
itself. head, tail = l and head, *tail = l mean something completely
different, and the only difference is a constraint placed on tail,
which forces the semantics to be different; the righthand side, or
what is to be assigned, is identical. Of course one can just regard it
as syntactic sugar for head, tail = unpackheadandtailaslist(l); but
the syntactic sugar achieves that same end through a type constraint
on tail. Really.
You are jumping to conclusions about implementation details which aren't
supported by the visible behaviour. What evidence do you have that
iterator unpacking creates a tuple first and then converts it to a list?

You are jumping to conclusions about my opinion which aren't supported
by my visible behaviour. What evidence do you have that I ever even
said any such thing?
Iterator unpacking is no more about type constraints than is len().

Because you wish to keep nitpicking about my usage of the term 'type
constraint' (even though you have not introduced an alternative term
yourself), or because you actually disagree with the content of my
message?
 
E

Eelco

I like the spirit of this. Let's look at your examples.

Glad to see an actual on-topic reply; thanks.
My initial reaction was "nonono!", but this is simply because of the ugliness. The double-colon is very visually busy.

I would have preferred the single colon, but its taken. But exactly
this syntax is used in other languages (for what that is worth...)
I find that your second example is inconsistent with the others. If we say that the variable-name is always on the right-hand-side, we get:


This nicely mirrors other languages (such as in your C# example:  "float foo") as well as the old python behavior (prefixing variables with */** to modify the assignment).

The link in my OP has the BDFL discussing type constraints; he also
prefers identifier:type. Many modern languages have something similar.
How is my second example inconsistent?
As for the separator, let's examine the available ascii punctuation. Excluding valid variable characters, whitespace, and operators, we have:

! -- ok.
" -- can't use this. Would look like a string.
# -- no. Would looks like a comment.
$ -- ok.
' -- no. Would look like a string.
( -- no. Would look like a function.
) -- no. Would look like ... bad syntax.
, -- no. Would indicate a separate item in the variable list.
. -- no. Would look like an attribute.
: -- ok, maybe. Seems confusing in a colon-terminated statement.
; -- no, just no.
? -- ok.
@ -- ok.
[ -- no. Would look like indexing.
] -- no.
` -- no. Would look like a string?
{ -- too strange} -- too strange

~ -- ok.

That leaves these. Which one looks least strange?

float ! x = 1
float $ x = 1
float ? x = 1
float @ x = 1

The last one looks decorator-ish, but maybe that's proper. The implementation of this would be quite decorator-like: take the "normal" value of x, pass it through the indicated function, assign that value back to x.

I dont think thats too proper an analogy. The type constraint does not
just coerce the content that is bound to the variable, it influences
the semantics of the whole statement; so insofar there is a suggested
relation with decorators, id rather not have it.

Try these on for size.

     head, @tuple tail = sequence
     def foo(@list args, @dict kwargs): pass
     foo(@args, @kwargs)

For backward compatibility, we could say that the unary * is identical to@list and unary ** is identical to @dict.

Yes, maximum backwards compatibility would be great.
 
E

Eelco

On 12/17/2011 22:52, buck wrote:> Try these on for size.



I like this idea much more than the original one. In addition to the
arguments buck puts forth, which I find compelling, I have one more: you
go to great length to say "this isn't really type checking in any sense"
(which is true)... but then you go forth and pick a syntax that looks
almost exactly like how you name types in many languages! (In fact,
except for the fact that it's inline, the 'object :: type' syntax is
*exactly* how you name types in Haskell.)

No, its not type *checking*, its type *declaration*. I tried to go to
great lengths to point that out, but it appears I did not do a very
good job :). Type declaration is exactly what I want, and insofar this
syntax has already found adoptation elsewhere, ill consider that a
plus.
I have a bigger objection with the general idea, however.It seems very
strange that you should have to specify types to use it. If the */**
syntax were removed, that would make the proposed syntax very very
unusual for Python. I could be missing something, but I can think of any
other place where you have to name a type except where the type is an
integral part of what you're trying to do. (I would not say that
choosing between tuples and lists are an integral part of dealing with
vararg functions.) If */** were to stick around, I could see 99% of
users continuing to use them. And then what has the new syntax achieved?

Good point; technically the askeriskes could be kept for backwards
compatibility, but that would break 'there should only be one way to
do it'. Indeed it would be unusual for python to have to explicitly
name a type, but implicitly ** does very much the same. Its just a
cryptic way of saying 'dict please'.
You can fix this if you don't require the types and just allow the user
to say "def foo(@args)" and "foo(@args)". Except... that's starting to
look pretty familiar... (Not to mention if you just omit the type from
the examples above you need another way to distinguish between args and
kwargs.)

Yes, one could opt for a syntax where the collection type is optional
and a sensible default is chosen, But to me that would largely defeat
the point; I very much like the added verbosity and explicitness. args-
tuple and kwargs-dict; that just has a much better ring to it than
star-star-kwargs, or whatever other cryptic symbol you use.
I have one more suggestion.

I do have one more thing to point out, which is that currently the
Python vararg syntax is very difficult to Google for. In the first pages
of the four searches matching "python (function)? (star | asterisk)",
there was just one relevant hit on python.org which wasn't a bug report.
I certainly remember having a small amount of difficulty figuring out
what the heck * and ** did the first time I encountered them.

This would suggest perhaps some keywords might be called for instead of
operators. In the grand scheme of things the argument packing and
unpacking are not *all* that common, so I don't think the syntactic
burden would be immense. The bigger issue, of course, would be picking
good words.

This also helps with the issue above. Let's say we'll use 'varargs' and
'kwargs', though the latter too well-ingrained in code to steal. (I
don't want to get too much into the debate over *what* word to choose.
Also these don't match the 'head, *tail = l' syntax very well.) Then we
could say:
  def foo(varargs l, kwargs d):
      bar(varargs l, kwargs d)
and varargs would be equivalent to * and kwargs would be equivalent to
**. But then you could also say
  def foo(varargs(list) l, kwargs(dict) d)

I agree; I had the same experience. But according to others our
opinion is wrong, and we should just become better at using google.
 
S

Steven D'Aprano

Casts or conversions are a runtime concept; im talking about
declarations. That seems to be the source of your confusion.

Everything in Python happens at runtime, apart from compilation of source
code into byte code. Python doesn't have declarations. Even class and def
are statements which happen at runtime, not declarations which happen at
compile time.

Your proposal will be no different: if it happens, it will happen at
runtime.


[...]
I guess this use of the term entered my lexicon through the
C# developer team. Either way, you seem to be the only one who does not
grok my intended meaning, so I suggest you try reading it again.

I grok your *intended* meaning. I also grok that you are using the wrong
words to explain your intended meaning.

"head, *tail = iterable" is not a declaration in Python. It is not a type
conversion, or a constraint, or a cast. It is an iterator unpacking
operation. It is syntactic sugar for something similar to this:

tmp = iter(iterable)
head = next(tmp)
tail = []
try:
while True:
tail.append(next(tmp))
except StopIteration:
pass
del tmp


The only constraint is on the *input* to the operation: the right hand
side object must obey the iterator protocol. The only conversion (if we
want to call it such) is that an iterator object is created by the right
hand side object.

[...]
head, tail = l and head, *tail = l mean something completely different,

They are both iterator unpacking, and therefore by definition not
"completely different". The first one is syntactic sugar for something
like this:

tmp = iter(iterable)
head = next(tmp)
tail = next(tmp)
if tmp is not empty: raise exception
del tmp


and the second as shown earlier. Clearly they are quite similar: the only
difference is that in the first case, the right hand side must have
exactly two items, while in the second case, the right hand side can have
an arbitrary number of items.

and the only difference is a constraint placed on tail, which forces the
semantics to be different; the righthand side, or what is to be
assigned, is identical. Of course one can just regard it as syntactic
sugar for head, tail = unpackheadandtailaslist(l); but the syntactic
sugar achieves that same end through a type constraint on tail. Really.

All the words are in English, but I have no understanding of what you are
trying to say here. What is unpackheadandtailaslist and how does it
differ from actual unpacking in Python?

You are jumping to conclusions about my opinion which aren't supported
by my visible behaviour. What evidence do you have that I ever even said
any such thing?

My evidence was your actual words, quoted in my post, which you deleted
in your response.

Here they are again:

This changes the semantics from normal unpacking, to unpacking
and then repacking all but the head into a list.
[end quote]

In context, "this changes..." refers to extended iterator unpacking in
the form "head, *tail" contrasted with "head, tail =...", and that it
generates a list.

It may very well be that I have misunderstood you. If you do not intend
the meaning that extended tuple unpacking first unpacks to a tuple and
then re-packs to a list, then please explain what you did mean.

Because you wish to keep nitpicking about my usage of the term 'type
constraint' (even though you have not introduced an alternative term
yourself), or because you actually disagree with the content of my
message?

I don't think much about your proposal. I think it is unnecessary, based
on a profound misunderstanding of how Python actually operates, badly
explained using inappropriate terms, and the syntax you propose is ugly.
 
E

Eelco

Everything in Python happens at runtime, apart from compilation of source
code into byte code. Python doesn't have declarations. Even class and def
are statements which happen at runtime, not declarations which happen at
compile time.


Of course it will have runtime effects; and compile/interpret-time
effects too. You said as much yourself: 'Everything in Python happens
at runtime, apart from compilation of source'.

Python *does* have declarations. Even though they may not be called
such in the documentation (dunno, havnt checked) the current use of *
and ** when not signifying collectiong UNpacking, is an annotation to
the declaration of the symbol that comes after it. In this case, a
constraint-on / specification-of the type of the object that the
variable symbol may bind; a list or tuple, depending on the context.
Your proposal will be no different: if it happens, it will happen at
runtime.

At least something we agree upon; all im proposing is an alternative
syntax for something thats already there. Lets be pragmatic and agree
to disagree on what it is that is already there, or what it ought to
be called. Because frankly, this has detracted enough already from
what it is I do want to discuss.
[snipped staements of the obvious]

and the second as shown earlier. Clearly they are quite similar: the only
difference is that in the first case, the right hand side must have
exactly two items, while in the second case, the right hand side can have
an arbitrary number of items.

Oh great, you found another semantic hair to split. Yes, they are
quite similar. Nonetheless, any python implementation that would
confuse the two behaviors would be considered badly bugged.

All the words are in English, but I have no understanding of what you are
trying to say here. What is unpackheadandtailaslist and how does it
differ from actual unpacking in Python?

I have the impression you are not even trying then. Google 'syntactic
sugar'. It means 'semantically identical way of putting things', in
short. That tells you everything you need to know about
unpackheadandtailaslist: nothing.
You are jumping to conclusions about my opinion which aren't supported
by my visible behaviour. What evidence do you have that I ever even said
any such thing?

My evidence was your actual words, quoted in my post, which you deleted
in your response.

Here they are again:

   
    This changes the semantics from normal unpacking, to unpacking
    and then repacking all but the head into a list.
    [end quote]

In context, "this changes..." refers to extended iterator unpacking in
the form "head, *tail" contrasted with "head, tail =...", and that it
generates a list.

It may very well be that I have misunderstood you. If you do not intend
the meaning that extended tuple unpacking first unpacks to a tuple and
then re-packs to a list, then please explain what you did mean.

Again, where did I say it first unpacks to a tuple? As far as im aware
that only happens in the context of a function call.
I don't think much about your proposal. I think it is unnecessary, based
on a profound misunderstanding of how Python actually operates, badly
explained using inappropriate terms, and the syntax you propose is ugly.

Which is not an aswer to the question I posed; just an expression of
frustration.

Its mutual.
 
E

Evan Driscoll

The barrier to new keywords in Python is very high. Not going to
happen for something that already has perfectly good syntax already
familiar to Python and Ruby programmers. Might else well try to get C
and Java to stop using "..." (ellipses).
I agree to some extent; I did say my suggestion was somewhat an effort
in brainstorming. (Though I would point out that, if you accept the
premise of this PEP suggestion, "perfectly good" only sort of applies.)
The burden is that you complicate the compiler and reduce the pool of
useful names available to the programmer. To be useful, the keywords need
to be short, meaningful and memorable -- which means they're already used
in code, which you will break needlessly.
OTOH, it wouldn't be the first time it was done. For instance, 'with'.
With operators that otherwise would be illegal, the programmer doesn't
need to learn about varargs until they need to. With keywords, the
programmer needs to learn "you can't use varargs or kwargs as variable
names" practically from day 1.
Yes, but it's not exactly a hard lesson. I can't think of any time where
you'd have ambiguous syntax, so misuse could always produce a good error
message. And keyword highlighting is something that basically all
editors can do well... so unless you're opposed to using an editor more
advanced than Notepad, you'll type in "varargs", it'll turn purple or
whatever, and you'll go "oh that's a keyword."

So you're not just adding keywords, you're adding new syntax: something
which looks like a function call, but isn't a function call.
Well, almost by definition these proposals consider adding syntax.
I'm going to pose the same question to you I have already posed to Eelco:
in your proposal, what happens if the caller has shadowed the list built-
in? Does argument l become a built-in list, or does it become whatever
type list is currently bound to?

Some more questions:

Can varargs accepted arbitrary callables, or only a fixed set of known
types?

How does this differ from what can be done with annotations?
These are questions I don't feel I can answer very well. I was giving my
thoughts on what I would do or consider doing with the proposal assuming
the fundamental idea is sound. Whether it should be accepted at all is a
matter for someone else. :)

Evan



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJO7kNoAAoJEAOzoR8eZTzgHAMIAJk1z0VGyZaANFCK4Yxe6iOV
3tEVY6iNx3Ky4ggkfUirGxsVWYBg7DMU9l1O0ALG0U+G9peY9vC9RL7bR9naqBEY
eeQhuIqKljmLxsc5uxdifatIxoicbx+JxZwijr0IkM2BkO2wkQ6erQ1HiuRTg37J
FlJ9z8loP/F3aYJf7nKf9y+/40qWzLJSnCHaX/PLmDMi0TP6kDgs15EmXdxqLI4o
sEEwxvNnR71HP8Wn49EDqeUbQwt5Usuv+t+k4KtQAGGGKyCdkKZ1tNF5Ym1ECM7d
UvxaoUOc9o1G8opRdJ3kjksv/7hpuPxwZb2HseDgaC1VCaYWMb4iA3Xi/1Obfo8=
=VVtn
-----END PGP SIGNATURE-----
 
E

Evan Driscoll

And rebutted. Modesty[1] prevents me from quoting myself, but here are
some links to searches:

http://duckduckgo.com/?q=python+asterisk
http://duckduckgo.com/?q=python+*
OK, so if you search using the right search engine, you *might* get a
link to the Python docs. (As I pointed out in a reply to myself before,
you *do* get relevant hits with my Google searches as well, but
virtually nothing to the relevant Python documentation.)

My thinking is borne out; I asked a friend who didn't know what it did
to find out, and he went to Google with the search "python 'starred
argument'", which he said led to moderately helpful results, but again
none from the actual Python docs.
My normal first place to look for something is Wikipedia. Enjoy it before
SOPA kills it.

http://en.wikipedia.org/wiki/Asterisk#Programming_languages
I might think to look at the Wikipedia article for *Python* (which, by
the way, doesn't help); looking at the wikipedia page for *asterisk*
wouldn't even enter my mind.

Your search looks overly complicated to me.

I'm not an expert on Google's syntax, but if you search for "python,
optionally with function", isn't that the same as just searching for
"python" since it will return hits either with or without "function"?
Chris Angelico's interpretation is correct: I did four searches, "python
function star", "python function asterisk", "python star", and "python
asterisk".

Evan



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJO7kVhAAoJEAOzoR8eZTzgrTsIAIGEyWgJ/B36IfFkI9gBXryG
92bYVcuUECenKevSy4m3lsdmkP2cO7/iuYAsGLMmVV1GX8lv1uZq8jxYpnbJRx6i
pYunmDGLOs+4vudprq/dwsRfFEVXpACfKJLyZJDC4BVQZCeG72ovxI1pt7Yr1pHy
XoqzWf3m45Ll6aKi3mS40InIL1w2v624dWfjFtgtpO4SVjRBlK4UcLfugeLjjtYo
L9RHgmO8oemW5wF6r89/8FPjmSFZDvOr3n15IkLnrCuutIekY6T7G9OvyOv5hEag
kydDiDLNpoQ0AlLZnMsXMqBv7wbDbWRYnkVd7sLILekLBE0+knrtrTsMvGU5aVM=
=N8Ku
-----END PGP SIGNATURE-----
 
E

Evan Driscoll

No, its not type *checking*, its type *declaration*. I tried to go to
great lengths to point that out, but it appears I did not do a very
good job :). Type declaration is exactly what I want, and insofar this
syntax has already found adoptation elsewhere, ill consider that a
plus.
You say it's found adoption elsewhere, but I think it's that adoption
which makes it a *bad* idea, because it does something entirely
different in those situations. Other languages are using that syntax for
something which is statically checked -- you are proposing that syntax
for a dynamic conversion.

look pretty familiar... (Not to mention if you just omit the type from
the examples above you need another way to distinguish between args and
kwargs.)

Yes, one could opt for a syntax where the collection type is optional
and a sensible default is chosen, But to me that would largely defeat
the point; I very much like the added verbosity and explicitness. args-
tuple and kwargs-dict; that just has a much better ring to it than
star-star-kwargs, or whatever other cryptic symbol you use.
My problem with it is that it in some sense is forcing me to make a
decision I don't care about. Yes, what we have now is less flexible, but
I have *never* said "man, I wish this *args parameter were a list
instead of a tuple". So at least for me, making me say "args::tuple" or
"@tuple args" or whatever is just changing the syntax a bit and adding
several more characters for me to type.

Evan



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJO7ksEAAoJEAOzoR8eZTzgQgEH/RE0p/m73SOEmj2gdjVPWPG0
KLU261cafSesKtc1+eglkcDqZ4tLW18010D8ixh6KIY6C0S4dv/x85x2gHDWcmBc
RXKCcqKDrBlFdy1en9S1sil3zUbllCWxTXSHCipf6VblOfFIEenAEzyzw3991+jK
IzezfQaDkosrORvsG10cDCfLRln6eAXiBoIuTJI0ySJ21EE/e+z9fp/tUQ/4Sl4Q
YqB+MmGVvu4gxN+ynYV+OPHdcysuO9tiTX5ow0DZO5R42yDhtbhK6PWzkAHzCUqg
CFkcUQ20q5b+HmGjh18HtHYFySTvkf9k8cupOIl9J2Ev8qOsLNv2zz7Z/470Wi0=
=glXh
-----END PGP SIGNATURE-----
 
R

Rick Johnson

[...]
As for the separator, let's examine the available ascii punctuation. Excluding valid variable characters, whitespace, and operators, we have:

! -- ok.
No, there are better uses for that char.
" -- can't use this. Would look like a string.
# -- no. Would looks like a comment.
$ -- ok.
No, there are better uses for that char.
: -- ok, maybe. Seems confusing in a colon-terminated statement.
dear god no!
; -- no, just no.
? -- ok.
No, there are better uses for that char.
YES!
 
R

Rick Johnson

On 12/17/2011 22:52, buck wrote:> Try these on for size.



I like this idea much more than the original one.

+1. I will second that! Eelco has the CORRECT idea, but the WRONG
syntax!
 
R

Rick Johnson

On Dec 18, 6:33 am, Evan Driscoll <[email protected]> wrote:
Good point; technically the askeriskes could be kept for backwards
compatibility, but that would break 'there should only be one way to
do it'.

I believe it's high time for the upper society of this community to
realize that the small breaks in backward compatibility in Python 3000
were only the beginning. Python is evolving past even what Guido could
have dreamed. He can not hold the reins of this unwieldy beast any
longer.
 
S

Steven D'Aprano

On Sun, 18 Dec 2011 13:47:46 -0600, Evan Driscoll wrote:

[...]
so unless you're opposed to using an editor more
advanced than Notepad, you'll type in "varargs", it'll turn purple or
whatever, and you'll go "oh that's a keyword."

Not everybody uses editors more advanced than Notepad. Even those who do
may not have an editor that understands Python keywords, or has an
obsolete list of keywords (my editor of choice doesn't know about
NotImplementedError). Or they're ssh'ed into a customer's server half-way
across the world and using `ed` because that's the only thing available.

The point is not that there can never been more keywords in Python, but
that the burden of proof is on those asking for new keywords. By default,
the status quo wins:

http://www.boredomandlaziness.org/2011/02/status-quo-wins-stalemate.html
 
R

Rick Johnson

Not everybody uses editors more advanced than Notepad.
And they have no excuse for NOT using a better one. Well, except for a
"foolish consistency" that is!
Even those who do
may not have an editor that understands Python keywords, or has an
obsolete list of keywords (my editor of choice doesn't know about
NotImplementedError).

Are you kidding me? Any editor that is not smart enough to do....... needs to be thrown out the window.

And let's not forget that Python even ships with an IDE called IDLE.
As poorly written as IDLE's code may be, at least it is smart enough
to find the current keyword list.
 
A

alex23

Evan Driscoll said:
My problem with it is that it in some sense is forcing me to make a
decision I don't care about. Yes, what we have now is less flexible, but
I have *never* said "man, I wish this *args parameter were a list
instead of a tuple".

And if you _did_, then one of the first lines in your function would
be:

args = list(args)

Which is obvious to everyone, doesn't modify existing behaviour,
doesn't force everyone without a fetish for change to add unnecessary
cruft to their function signature...

Except, OMG, list() is RETURNING A LIST, which is an OBVIOUS type
constraint. I propose that:

args = @set list(args)

Will coerce args into a list and then give me a set in return.
 

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,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top