Interesting... after discussing quite a bit about the feature and their issue most of us now focus to the roadmap to follow. We're on the right way, we still don't know witch way... but it seems to be the right one.
I agree with many thing told before:
- first do not add new syntax but prefer using current syntax to do the stuff... then add a new syntax when needed by the intensive usage ^_^ (cf the decorator evolution)
- adaptation is the most flexible thing and it is really advanced right now so it's must be the first thing to do
- pre/postconditions are quite hard to deal with *but* could be a major improvement if well done (what means clean inheritance of pre/postcondition just as in eiffel or planned for the D language)
so here is the roadmap with exemple for each step... it's easier for me to understand like this:
1 - adaptation adaptation at runtime of parameters is really very flexible and the PEP is quite advanced... so let's do it first!
def foo(arg1, arg2):
#do the adaptation here at run time
2 - standard type checking decorators it is very easy to have such stuff (exemple implementation (but not standardized could be found in PEP 318)
@accepts(int, int)
@returns(list)
def foo(arg1, arg2):
#foo code here
now we have two major features... for low cost... let's deal then with harder stuff...
3 - advanced type operations let's make the type behave like sets (what is academicaly not so dumb ^_^ ). It would allow very good compliance between adaptation at run time and typechecking.
@accepts(str | url , int)
@returns(list)
def foo(arg1, arg2):
#do the adaptation here at run time
4 - interface/protocolshave a nice way to define protocols (I think this term is nearer of the exact purpose: definig a behaviour). This for me should define a new type (but not a class) and therefore it needs a new syntax... let's deal with the Guido's one (I like it it I do not see any other).
interface MyInterface:
def foo1(arg1, arg2):
"""do some stuff 1"""
def foo2():
"""do some stuff 2"""
def foo3(arg1):
"""do some stuff 3"""
And here MyInterface is a type not a class and it could be used like a type (including the "sets-like" operations)
5 - pre/post conditionwhat kind of syntax could be used without changing the syntax at all? Really I don't know... if I did I would have used it for a long time... here is a proposition I'm currently working on using decorator (yes decorators are my favorite toys ^_^ ). It allows definition of condition on the fly using lamda function or to reuse previously defined function.
def invariant1():
assert stuff is not nil
@precondition(invariant1)
@precondition(lambda arg1 : assert arg1 > 0)
@precondition(lambda arg2 : assert arg2 > 0)
@postcondition(lambda result : assert result is not nil)
def foo():
#foo code here
(this code is just here to show that it is possible to do something without adding new feature but implementation syntax *have to* be discussed.
5 - parametrised type It comes last because (for me) it's the less useful and it is quite complicated to have somthing good : syntax, usefulness, readability...
my_list1 = list[int]()
my_list2 = list[int | str]()
Now let's go further
So now it would be interesting to discuss where and how each point have to evolve... here all the exemples were simple exemples to show that we could tests many stuff before dealing with language change. For exemple it would be interesting to first follow existing PEP and create new ones. Then many feature could be include in the lib and then maybe the most useful feature could appear in the language it self.
I know it could be a long long way... but it is a safe and smart way!
sample of feature evolution
Here is an exemple of feature evolution: the static typing:
- proposition of implementation using decorators:
@accepts(int, int)
def foo(arg1, arg2):
#code here
- discussion/PEP leads to a modification of the prototype to have a more flexible thing:
@accepts(int, int)
def foo1(arg1, arg2):
#code here
@accepts(arg1 = int, arg2 = int)
def foo2(arg1, arg2):
#code here
- feature added to the library (yeepee!):
from decorators import *
@accepts(int, int)
def foo1(arg1, arg2):
#code here
@accepts(arg1 = int, arg2 = int)
def foo2(arg1, arg2):
#code here
- as it is commonly used by a lot of people a new PEP opens about adding this feature to the language or not and with witch syntax...
- if everything goes well the feature is added to the language:
def foo1(arg1 : int, arg2: int):
#code here
But it is just one scenario... anything could stop earlier... maybe it's not a good idea to go so far. Maybe decorator is enough, maybe noone will use this, maybe even the decorator version will be refused as a standard... (for me it would be stupid because it fulfill the requirement for static type checking/information and so enable any kind of documentation/optimisation... but it's just my opinion).
So let's discuss all those things!!!