On 2020-02-09 4:46 p.m., Andrew Barnert wrote:
> On Feb 9, 2020, at 05:40, Soni L. <fakedme...@gmail.com> wrote:
> > I'd rather have arg decorators tbh. they feel more natural than hacking on the type annotations.

Annotations look a lot more natural to me here.

Maybe that’s because your only example (besides the useless original one) looks 
like an implicit cast a la C++ and zillions of other languages:

    void cheese(Spam spam) {
        // whatever
    }

    Eggs eggs(42);
    cheese(eggs);

Oversimplifying the C++ rules a bit, this will call the Spam::Spam(Eggs) 
constructor on eggs to get a Spam, and that will be the value of spam. Which is 
exactly what you’re trying to do, so spelling it similarly seems reasonable:

    @implicit_cast
    def cheese(spam: Spam):
        # whatever

    eggs = Eggs(42)
    cheese(eggs)

This would of course raise a TypeError at runtime instead of at compile time if 
there is no way to construct a Spam from an Eggs, and it requires a decorator 
because it’s not built deep into the language as it is in C++, but otherwise 
it’s the same idea and the most obvious way to translate its spelling.

Maybe if you had a good example that wasn’t an implicit type cast, this 
similarity would be an argument against using annotations rather than an 
argument for using them? But it’s hard to know without seeing such an example, 
or even knowing if you have such an example.

That's C++. But consider this:

class Foo:
  def bar(self):
    pass

x = Foo()
y = x.bar

The traits thing is just as much of an implicit cast as Python methods are an implicit cast. Which is to say, it isn't. Traits don't have a constructor - instead, calling them with an object will, if the object allows it, create a wrapper object to handle the trait method lookups and any necessary wrapping or unwrapping of objects. This is also the way to access conflicting names: MyTrait(MyClass()).x() is defined in the @impl(MyTrait) (and does print("Hello,") then print("World!")), whereas MyClass().x() is the inherent method in MyClass (and only prints "World!"). Note also that the @impl gets the full unwrapped object, and not a TraitWrapper - this is by design.

This has many parallels to how methods in python do the "self" thing, altho I can understand the confusion if you're not familiar with traits in e.g. Rust.

> I'd need to create wrapper functions and deal with mixed args and kwargs. as 
far as I know there aren't libraries that do it for me, either.

You only need to create one decorator that creates wrapping functions. There is 
a library that deals with args and kwargs for you, and it comes with Python: 
inspect. There are also libraries in PyPI to help write decorators, to do 
cast-like stuff, etc. If there isn’t a library that puts it all together the 
way you want, then that probably means there isn’t nearly enough demand for 
this feature to even put it in the stdlib, much less add new syntax for it. But 
that also means you can write it yourself and put it on PyPI and proselytize 
its use, and maybe create that demand.
Don't forget: kw-only arguments, positional-only arguments, arguments that can be either, default values, etc.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/P5APZZX7L56YIMKAON7YKD274WAXLUNB/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to