acton icon indicating copy to clipboard operation
acton copied to clipboard

Remove need for @property, i.e. infer class attribute slot for storing function references as object property attribute, not class method

Open plajjan opened this issue 6 months ago • 3 comments

def haha():
    return "haha"

def hoho():
    return "hoho"

class Foo(object):
    a: int
    @property
    b: mut() -> str

    def __init__(self, a: int, b: mut() -> str):
        self.a = a
        self.b = b


actor main(env):
    f1 = Foo(1, haha)
    f2 = Foo(2, hoho)

    print(f1.b())
    print(f2.b())

    env.exit(0)

If we remove @property we get:

[error]: Non @property attribute b cannot be mutated
     ╭──▶ foo.act@13:14-13:15
     │
  13 │         self.b = b
     •              ┬
     •              ╰╸ Non @property attribute b cannot be mutated
─────╯

@nordlander is this intentional or a bug?

plajjan avatar Jul 06 '25 01:07 plajjan

The general idea is that defined methods of a class are stored in its method table, while the attributes initialized in __init__ get allocated in each created instance of the class. But for an abstract attribute we have neither a def nor an __init__ assignment, only a type signature. So here the rule of thumb is that a signature specifies a yet-to-be-defined slot in the method table if it is of function type, and an abstract instance variable in every other case.

However, the case where one wants an abstract instance variable to have a function type then needs some special handling, and for this reason I applied Python's @property decorator to mean "instance variable no matter what". And in fact, internally the compiler now relies exclusively on this decorator, so the rule of thumb is above is actually just a principle for inferring @property decorators if they are not explicitly set.

I originally thought this was a great idea, but in the light of our more recent discussions on the class syntax I'm not so sure anymore. It just feels too complicated. Moreover, the example above isn't really defining abstract attributes, it just contains a redundant signature that happens to fool the compiler onto the "abstract" decision path before it sees the __init__ assignments. Maybe this particular situation could be fixed, but I'd like to take a more general grip of this whole question when we modernize the class syntax.

nordlander avatar Jul 06 '25 14:07 nordlander

Okay, I see. I can see how it felt clever but ISTM that with a bit more analysis we can sort out which attributes are set in init and sort them out from abstract type specs, protocol extensions etc

so if I preserve it in the internal AST I get the desired semantics in types / codegen etc. I can give it a try to do a little more analysis up front to try and avoid the explicit @property

plajjan avatar Jul 07 '25 01:07 plajjan

The analysis is already there, it’s just that when there’s a signature as well the compiler stupidly concludes that the attribute must be abstract — at least concerning the inference of @property.

So please go ahead and change this if you like. It should just be about taking init assignments into account even for attributes that have signatures.

Message ID: @.***>

nordlander avatar Jul 07 '25 16:07 nordlander