Verbose and flexible args and kwargs syntax

2011-12-11 Thread Eelco Hoogendoorn

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.


A more readable form occurred to me, which also happens to be more 
flexible, and which I think is fully compatible with the syntax of the 
language:


def func(parg, list(args), dict(kwargs))

Perhaps this is considered abuse of notation; dict(kwargs) already has a 
meaning rather different from the one we try to give it here; but then 
again the context (being inside a function definition) is unique and 
easily recognizable.


An added advantage would be the possibility of using subclasses of dict 
and list as well; imagine how much more beautiful a lot of code would be 
if one could say


def func(attrdict(kwargs))

Problems im still wrestling with: the same syntax could not be used when 
calling a function; that lack of symmetry would make things more 
confusing, not less.


Thoughts?
--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-11 Thread Eelco Hoogendoorn

 Yes, that's just a strict keywordification of the * and ** symbols.
 The same argument could be made for eliminating the standard algebraic
 + operator and replacing it with a keyword "__add__". I don't think
 that's worthwhile.



Well, its not quite the same in the sense that algebraic operators are 
essentially part of 'natural language', or at least extremely widely 
adopted. They have earned their own special symbols. Argument 
packing/unpacking is a very specific thing; a small corner of a 
particular programming language.


However, as seen in the light of python 3 head-tail syntax, perhaps the 
above is not quite true, and one could argue that packing/unpacking of 
collections is indeed a quite general concept, deserving of its own 
symbols. Breaking uniformity with that use case would also be a bad 
thing; ideally, a verbose alternative to all occurances of collection 
packing/unpacking would be available.


That said, a more verbose and flexible syntax would be desirable there 
too; as of now, the tail is always a list. I havnt read the discussions 
leading up to those design decisions, but that seems like a compromise 
to me; something like head,tuple(tail) = someiterable would be 
preferrable there too, id say

--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-11 Thread Eelco Hoogendoorn
As for syntax; what about coopting/integrating with the function 
annotation syntax?


so:

def func(args: list, kwargs: attrdict)
and correspondingly in the function call?

a, b:tuple = someiterable?

I guess a rule that interprets every function argument annotated as a 
subclass of list or dict as a special case would severely restrict its 
intended use though...

--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-11 Thread Eelco Hoogendoorn

 No more so than any other form of punctuation. Plus and minus + - may be
 so common that just about everyone knows it, but how about | == @ % and
 even . (dot)? None of these things will be obvious to newbies who have
 never programmed before. Oh well.



 Some things you just have to learn.



Yes, some things you just have to learn. Nonetheless, I strongly prefer 
explicit logical operators over |, would much rather have 'equals' 
instead of ==, which is stylistic in line with 'is' and explicitly 
distinguishes between equality and identity comparisons. As for %; it is 
entirely unclear to me why that obscure operation ever got its own 
one-character symbol. Ill take 'mod', or even better, 'modulus' any day 
of the week.


The dot is clearly quantitatively in another realm here. 90% of typical 
python code is attribute accesses. The dot is entirely unambigious and 
cannot be mistaken for anything else. It reads like a book.



 It's a judgement call as to where a language divides "cryptic punctuation
 line noise" and "useful short operators", and in my opinion * and ** tuple
 and dict unpacking fall strongly on the "useful short operators" side.
 Your opinion may differ, but luckily for me, the BDFL agrees with me :)


I also agree that it is a value judgement as to which constructs get 
their own cryptic symbols and which do not, but the are some reasonable 
guidelines we should be able to agree upon. Obscure operations should 
not reserve any of the few available characters. Furthermore, the 
language should not just be formally consistent, but also easy to grasp 
at a glance, without deciphering subtle semantics of a blurb of weird 
characters. (some programming languages obviously disagree, but python, 
as far as I am allowed to speak for it, does not). And most importantly, 
if you cant come up with a terse syntax that does everything you want to 
do, the terse syntax should at best be an alternative to the verbose one.




 It is also misleading because args are not collected into a list, but
 into a tuple.


In case you wanted a tuple youd write tuple(args), obviously. Exactly that 
added flexibility is half of my case in favor. Why shouldnt it be a list when I 
want it to?




 Worse, it suggests that one should be able to generalise to
 something like this:



 def func(parg, str(args), int(kwargs), my_func(more_args)):



 which is incoherent.


Sorry, but I dont get this point at all. Does ** suggests one should be 
able to generalize to ***? The rules are the rules.




The real questions, in my mind, are:

1) How useful is this added flexibility? Not insanely, but I can see it 
making a lot of code significantly more clean.


And:

2) How fundamental is collection packing/unpacking? One can easily argue 
that it is indeed quite fundamental and therefore deserves its own terse 
symbols, I feel. However, if more flexibility is indeed deemed 
desirable, such terse syntax quickly gives way to a more verbose one. 
Can you come up with some terse symbols that will be able to express all 
of the below and dont make you wish you hadnt rather typed out the names?


head, tuple(tail) = iterable
head, list(tail) = iterable
head, str(tail) = somestring
head, generator(tail) = mygenerator

And so on.

If not, one has to admit that functionality is being sacrificed on the 
alter of terseness, which seems like a raw deal to me.

--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-11 Thread Eelco Hoogendoorn

 There are other means of finding information than Google. Really.


This is really only a very minor point in my argument, so I dont want to 
put the focus on this.


But really, no.

Googling 'myprogramminglanguage conceptimtryingtofigureout' is my first, 
second and third line of defence. Yes, I could read the reference manual 
from top to bottom, and if I already knew about the existence of your 
article then im sure that would be a great help too. But the situation 
one finds oneself in is seeing two asterikses and not even being aware 
they are particular to function definitions/invocations. Im fluent in 
many different languages and well versed in CS concepts and jargon, but 
I had no idea what to search for when first trying to figure out the 
meaning of these symbols, and that does not happen often to me.

--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-12 Thread Eelco Hoogendoorn

 The above examples are seldom needed in Python because we have one
 general method to repeatedly split a sequence into head and tail.



 it = iter(iterable) # 'it' now represents the sequenced iterable
 head = next(it) # 'it' now represents the tail after removing the head



 In other words, next(it) encompasses all of your examples and many more.
 Because 'it' is mutated to represent the tail, it does not need to be
 rebound and therefore is not.



The question in language design is never 'could we do these things 
before'. The answer is obvious: yes our CPUs are turing complete; we can 
do anything. The question is; how would we like to do them?


So do you think the new head/tail unpacking features in python 3 are 
entirely uncalled for? I personally quite like them, but I would like 
them to be more general.

--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-12 Thread Eelco Hoogendoorn

> No more, or less, explicit than the difference between "==" and "is".

== may be taken to mean identity comparison; 'equals' can only mean one 
thing. Of course 'formally' these symbols are well defined, but so is 
brainf*ck



 Modulo is hardly an obscure operation. "What's the remainder...?" is a
 simple question that people learn about in primary school.



So is 'how much wood would a woodchucker chuck if a woodchucker could 
chuck wood?'. But how often does that concept turn up in your code?


> And you can blame C for the use of % instead of mod or modulo.

I didnt know one of Python's design goals was backwards compatibility 
with C.



 I can't imagine what sort of Python code you have seen that you consider
 90% attribute access "typical". I've just run the Python tokenizer over
 my startup.py file, and I get these results:


Yes, that was a hyperbole; but quite an often used construct, is it not?


 If you can supply any function at all, what happens if I write this:



You cannot; only constructors modelling a sequence or a dict, and only 
in that order. Is that rule clear enough?


> I believe that your proposal leads to an over-generalisation "call
> arbitrary functions when handling parameter lists".

I hope the above clears that up. It is as much about calling functions 
as ** is about raising kwargs to the power of.


> I don't believe you
> need this added complication. If you want to your var args as a list,
> call list(args) inside your function.

We dont strictly 'need' any language construct. Real men use assembler, 
right?




 >/  head, tuple(tail) = iterable

/>  In Python 3, that is spelled:

 head, *tail = iterable
 tail = tuple(tail)


Yes, I know. How is that not a lot more verbose and worse than what I 
have proposed in all possible ways?


> head, tail = somestring[0], somestring[1:]

Well yes, splendid; we can do that with lists too since the dawn of 
Python. What you are saying here in effect is that you think the 
head/tail syntax is superfluous; that youd rather see it eliminated than 
generalized.


> head, tail = next(mygenerator), mygenerator

Which again of course works, but is yet again of entirely different form 
than any of the above solutions, while conceptually doing the same 
thing. Certainly, there is room for improved elegance here?
-- 
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-12 Thread Eelco Hoogendoorn

 On the contrary, it is a major point. You want us to change the language
 so you can program by Google. Sorry, aint't gonna happen.


On the contrary; I believe I get to decide which points I consider 
important. This one, I do not. Sorry for putting it in the first paragraph.

--
http://mail.python.org/mailman/listinfo/python-list


Verbose and flexible args and kwargs syntax

2011-12-12 Thread Eelco Hoogendoorn

> On the contrary, it is a major point.

Sorry, but im affraid it is up to ME to decide which point I feel are 
important. No, this is a minor point to me, and one that has been 
admirably put to rest by pointing out that spelling out the name of the 
symbol in google directly leads you to the information you are looking for.

--
http://mail.python.org/mailman/listinfo/python-list