On 2017-05-13 21:07, Simon Ramstedt wrote:
Hi, do you have an opinion on the following?
Wouldn't it be nice to define classes via a simple constructor function (as below) instead of a conventional class definition?
conventional: | classMyClass(ParentClass): def__init__(x): self._x=x defmy_method(y): z=self._x+y returnz |
| defMyClass(x): self=ParentClass() defmy_method(y): z=x+y returnz self.my_method=my_method # that's cumbersome (see comments below) returnself |
Here are the pros and cons I could come up with for the proposed method:
(+) Simpler and more explicit.
I don't really see how that's simpler or more explicit. In one respect
it's clearly less explicit, as the "self" is implicit.
(+) No need to create attributes (like
self._x) just to pass something
__init__ to another method.
Attributes aren't just for passing things to other methods. They're
for storing state. In your proposed system, how would an object mutate one of its own attributes? It looks like "x" here is just stored in a function closure, which wouldn't allow easy mutation. Also, how would another object access the attribute from outside (as we currently do with self.x)? You can say we'd only use this new attribute-free approach when we want to pass a constructor argument that's used but never mutated or accessed from outside, but that severely restricts the potential use cases, and all it saves you is typing "self".
Relatedly, how is ParentClass itself defined? I don't see how you
could bootstrap this without having a real class at the bottom of it somehow (as your test script in fact does).
(+) Default arguments / annotations for methods could be different for each class instance. Adaptive defaults wouldn't have to simulated with a None.
That seems as likely to be a negative as a positive. Having different
instances with different default values could be confusing. This would even allow different instances to define totally different methods (with if-logic inside the function constructor), which would definitely be confusing.
(+) Class/instance level imports would work.
How often is that really needed?
(-/+) Speed: The
def-based objects take
0.6 μs to create while the
class-based objects take only 0.4 μs. For method execution however the
closure takes only 0.15 μs while the proper method takes 0.22 μs (script
I don't think you can really evaluate the performance impact of this
alternative just based on a trivial example like that.
(-/+) Checking types: In the proposed example above
the returned object
wouldn't know that it has been created by
MyClass. There are a couple
of solutions to that, though. The easiest to implement would be to
change the first line to
self = subclass(ParentClass()) where the
subclass function looks at the next item in the call stack (i.e.
MyClass) and makes it the type of the object. Another solution would
be to have a special rule for functions with capital first letter
returning a single object to append itself to the list of types of the
returned object. Alternatively there could be a special keyword e.g.
classdef that would be used instead of
def if we wouldn't want
rely on the name.
Those special rules sound very hackish to me.
(-) The current syntax for adding a function to an object is cumbersome. That's what is preventing me from actually using the proposed pattern. But is this really the only reason for not using it? And if so, wouldn't that be a good argument for enabling something like below? attribute function definitions: | defMyClass(x): self=ParentClass() defself.my_method(y): z=x+y returnz returnself |
or alternativelymultiline lambdas:
| defMyClass(x): self=ParentClass() self.my_method=(y): z=x+y returnz returnself |
To be honest, from all your examples, I don't really see what the point
-- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown