Hi, thanks a lot for your feedback!<br><br><div class="gmail_quote"><div dir="ltr">On Sun, May 14, 2017, 00:54 Brendan Barnwell <<a href="mailto:brenbarn@brenbarn.net">brenbarn@brenbarn.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 2017-05-13 21:07, Simon Ramstedt wrote:<br>
> Hi, do you have an opinion on the following?<br>
<br>
        My general opinion is that imitating JavaScript is almost always a bad<br>
idea.  :-)<br>
<br>
> Wouldn't it be nice to define classes via a simple constructor function<br>
> (as below) instead of a conventional class definition?<br>
><br>
> *conventional*:<br>
> |<br>
> classMyClass(ParentClass):<br>
> def__init__(x):<br>
> self._x=x<br>
> defmy_method(y):<br>
>          z=self._x+y<br>
> returnz<br>
> |<br>
><br>
><br>
> *proposed*:<br>
><br>
> |<br>
> defMyClass(x):<br>
> self=ParentClass()<br>
> defmy_method(y):<br>
>          z=x+y<br>
> returnz<br>
> self.my_method=my_method # that's cumbersome (see comments below)<br>
> returnself<br>
> |<br>
><br>
><br>
> Here are the pros and cons I could come up with for the proposed method:<br>
><br>
> (+) Simpler and more explicit.<br>
<br>
        I don't really see how that's simpler or more explicit.  In one respect<br>
it's clearly less explicit, as the "self" is implicit.<br>
<br>
> (+) No need to create attributes (like `self._x`) just to pass something<br>
> from `__init__` to another method.<br>
<br>
        Attributes aren't just for passing things to other methods.  They're<br>
for storing state.  In your proposed system, how would an object mutate<br>
one of its own attributes?  It looks like "x" here is just stored in a<br>
function closure, which wouldn't allow easy mutation.  Also, how would<br>
another object access the attribute from outside (as we currently do<br>
with self.x)?  You can say we'd only use this new attribute-free<br>
approach when we want to pass a constructor argument that's used but<br>
never mutated or accessed from outside, but that severely restricts the<br>
potential use cases, and all it saves you is typing "self".<br></blockquote></div><div><br></div><div>Attributes could be added to self just as in conventional classes if they are needed.</div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
        Relatedly, how is ParentClass itself defined?  I don't see how you<br>
could bootstrap this without having a real class at the bottom of it<br>
somehow (as your test script in fact does).<br></blockquote></div><div><br></div><div>You could bootstrap with an object base class/constructor just as normal classes inherit from object. Also the normal class system should remain in any case in order not to break every python library.</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> (+) Default arguments / annotations for methods could be different for<br>
> each class instance. Adaptive defaults wouldn't have to simulated with a<br>
> None.<br>
<br>
        That seems as likely to be a negative as a positive.  Having different<br>
instances with different default values could be confusing.  This would<br>
even allow different instances to define totally different methods (with<br>
if-logic inside the function constructor), which would definitely be<br>
confusing.<br></blockquote></div><div><br></div><div>Different default values for different instances are a corner case but they are already happening by setting default to None. D<span style="font-size:13px">efining different methods for different instances wouldn't be good but that is also possible with conventional classes (by adding functions to self in __init__).</span></div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> (+) Class/instance level imports would work.<br>
<br>
        How often is that really needed?<br></blockquote></div><div><br></div><div>True, usually it doesn't matter. But when using big packages like tensorflow that take several seconds to load it can be annoying. Its always loaded when importing any library that uses it internally, because of module level imports that should be class/instance level. Even if we just wanted to do --help on the command line and needed that library before argparse for some reason.</div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> (-/+) Speed: The `def`-based objects take 0.6 μs to create while the<br>
> `class`-based objects take only 0.4 μs. For method execution however the<br>
> closure takes only 0.15 μs while the proper method takes 0.22 μs (script<br>
> <<a href="https://gist.github.com/rmst/78b2b0f56a3d9ec13b1ec6f3bd50aa9c" rel="noreferrer" target="_blank">https://gist.github.com/rmst/78b2b0f56a3d9ec13b1ec6f3bd50aa9c</a>>).<br>
<br>
        I don't think you can really evaluate the performance impact of this<br>
alternative just based on a trivial example like that.<br><br>Agree, I don't know really how well this would perform.<br></blockquote></div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> (-/+) Checking types: In the proposed example above the returned object<br>
> wouldn't know that it has been created by `MyClass`. There are a couple<br>
> of solutions to that, though. The easiest to implement would be to<br>
> change the first line to `self = subclass(ParentClass())` where the<br>
> subclass function looks at the next item in the call stack (i.e.<br>
> `MyClass`) and makes it the type of the object. Another solution would<br>
> be to have a special rule for functions with capital first letter<br>
> returning a single object to append itself to the list of types of the<br>
> returned object. Alternatively there could be a special keyword e.g.<br>
> `classdef` that would be used instead of `def` if we wouldn't want to<br>
> rely on the name.<br>
<br>
        Those special rules sound very hackish to me.</blockquote></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> (-) The current syntax for adding a function to an object is<br>
> cumbersome.  That's what is preventing me from actually using the<br>
> proposed pattern. But is this really the only reason for not using it?<br>
> And if so, wouldn't that be a good argument for enabling something like<br>
> below?<br>
> *<br>
> *<br>
> *attribute function definitions*:<br>
> |<br>
> defMyClass(x):<br>
> self=ParentClass()<br>
> defself.my_method(y):<br>
>          z=x+y<br>
> returnz<br>
> returnself<br>
> |<br>
><br>
><br>
> or alternatively*multiline lambdas*:<br>
><br>
> |<br>
> defMyClass(x):<br>
> self=ParentClass()<br>
> self.my_method=(y):<br>
>          z=x+y<br>
> returnz<br>
> returnself<br>
> |<br>
<br>
        To be honest, from all your examples, I don't really see what the point<br>
is.  It's a different syntax for doing some of the same things the<br>
existing class syntax does, while providing no apparent way to do some<br>
important things (like mutating attributes).  I think Python's existing<br>
class syntax is simple, clear, and quite nice overall, and creating<br>
class instances by calling a function instead of a class doesn't add<br>
anything.  In fact, even JavaScript has recently added classes to allow<br>
programmers to move away from the old approach that you describe here.<br>
Also, as I alluded to above, JavaScript is so terrible in so many ways<br>
that the mere idea of imitating it inherently makes me skeptical;<br>
there's almost nothing about JavaScript's design that couldn't be done<br>
better, and most of what it does are things that Python already does<br>
better and has done better for years.  In short, I don't see any<br>
advantages at all to doing classes this way, and there are some<br>
non-negligible disadvantages.<br></blockquote></div><div><br></div><div>Interesting, didn't know that about Javascript. I also don't like Javascript's prototypes very much but thought adding "JavaScript-like" to the title might help explain what I meant.</div><div><br></div><div>Leaving the possible replacement for classes aside, do you have an opinion specifically about the following?</div><div><br></div><div>def obj.my_function(a, b):</div><div>   ...</div><div><br></div><div>as syntactic sugar for</div><div><br></div><div>def my_function(a, b):</div><div>  ...</div><div><br></div><div>obj.my_function = my_function</div><div><br></div><div>In my experience this pattern comes actually up quite a bit. E.g. when working with these "symbolic" machine learning frameworks like theano or tensorflow. Apart from that it mixins very easy. </div><div><br></div><div>What do you think are the odds of something like this actually making it into the Python and if greater than 0 in which timeframe?</div><div><br></div><div><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
--<br>
Brendan Barnwell<br>
"Do not follow where the path may lead.  Go, instead, where there is no<br>
path, and leave a trail."<br>
    --author unknown<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a></blockquote></div><div><br></div><div>Thanks,</div><div><br></div><div>Simon</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
</blockquote></div>