Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow writing to (default, never) in the constructor #4514

Closed
back2dos opened this issue Aug 31, 2015 · 7 comments
Closed

Allow writing to (default, never) in the constructor #4514

back2dos opened this issue Aug 31, 2015 · 7 comments

Comments

@back2dos
Copy link
Member

As a corollary of #4441, I would like to know if it would be possible to allow writing to (default, never) fields in the constructor?

Firstly, it can already be done with @:privateAccess, so it seems possible and secondly (default, never) is an otherwise meaningless combination, so it wouldn't affect any working code.

It would provide a much needed way to express runtime constant fields.

@nadako
Copy link
Member

nadako commented Sep 11, 2015

I think we discussed that before (with @Simn?) and the argument was that we can call some init function from a constructors that assigns to those fields and we cannot guarantee that it won't be called outside of constructor without interprocedural analysis (or something like that).

However I agree it would be useful to at least allow assigning to physical fields with never write accessor from the constructor.

@back2dos
Copy link
Member Author

Maybe I should clarify that by "in the constructor" I mean "in the constructor" and nothing else ;)

Whether or not there are some init functions is a different matter to me, that makes this whole issue insanely complex. For pooled objects, people might want to start calling init functions from outside the constructor and what not. If someone can offer a decent solution for these matters, then great, let's have it. I for one would be happy if the above worked and then we can see about the rest.

Also, people can do this.theField = theMethodThatCalculatesTheInitialValue(), to have something similar to init functions.

For that reason, I somewhat tend to disallow writing to (default, never) from subclasses, because if it becomes necessary, then the code could be refactored so that the super class uses a method to calculate the value that subclasses can override. On the other hand, it would not be very consistent with how liberal Haxe is when it comes to giving subclasses access to superclasses, so maybe just ignore the idea ;)

@ncannasse
Copy link
Member

I don't think that's a good design choice to allow something in the constructor that can't be done in other member functions. This will restrict the way users can express/factorize their code.

@back2dos
Copy link
Member Author

Uhm. Haxe itself is full of design choices that restrict how users can express their code. That is the nature of design choices. Haxe will have you use an abstract if you want operator overloading. Just saying.

Under the constraints that you yourself have put up, this I think is the most pragmatic thing to do to enable users to express immutability on fields.

What I really don't get is this notion that a single feature must solve ALL use cases - particularly the ones it was not designed for. The whole point of constants is that they may not be changed after the object was created. It is just silly to then say that constants are bad, because member functions cannot alter them. People can just continue to not use constants if they do want mutability. How does that restrict anyone?

@ncannasse
Copy link
Member

Saying that because there's already some restrictions then adding more is okay is not good reasoning IMHO : there are reasons why these previous restrictions were introduced in the first place (hopefully)

The problem I have with immutable fields in (default,never) is that they are not real immutable fields : you might be able to have several assigns in the constructors, or allow to subclass and the you can again assign in the constructor, unless the assignment is locked to the class that defines the field, but that's yet another somewhat arbitrary restriction, because traditional OO there is no actual clear semantics for immutable field.

However I agree with you that actually (default,never) does not make much sense and might then be used to implement real immutable fields.

Thinking more about it, this requires some extra restrictions to ensure the actual immutability:

  • ensure that the field is assigned in the constructor of the declaration class, and only once
  • don't allow any method call (or reading the field itself) before it is assigned

And in such case, yes I think we can talk about real immutable field, and the restriction on constructor does no longer seems arbitrary to me. We could add this but I wonder if the (necessary) restrictions will not cripple the feature so much that it does not get used by people.

@back2dos
Copy link
Member Author

Alright, let's not venture deeper into the generalist argumentation ;)

You are absolutely right in saying that the extra restrictions risk crippling the feature (or breaking existing code or both for that matter).

But are they really required?

Right now we even allow calling super constructors twice and hell doesn't break lose. It just takes some common sense on the side of the user, and I think we should carry over the assumption to this highly related issue.

Because in the end immutability is more useful to client code than the class itself. If as a user I construct a class with a field with (default, never), then once the constructor has relinquished control back to the call site I know the field is immutable. The optimizer can probably leverage that knowledge. I as a user certainly can. I don't have to worry about side effects of stuff I do changing the field. I know that the field access itself is thread safe. There's quite a number of rather far-reaching consequences. You surely know all this, but my point is that in contrast, being unable to initialize the same constant twice during construction has a very local effect. And under the assumption that the constructor is not the entry point into a convoluted ping pong of calls, the effect of being restrictive on statement ordering is equally local. On that local scale though, it does disallow things like this.constantField = this.calculateInitialValue(), which I think is overly restrictive on how one might want to structure code, causing more problems than it solves.

If one wants to be very specific about how and when constants should be initialized, then one enters very complex, subjective and opinionated terrain and I would say that's not for the language to solve, because not only does it risk crippling the feature as you've pointed out yourself, but people can enforce such specifics with macro based static analyzers without too much trouble.

What I do believe is that it is very reasonable for the language to have the how and when be bounded by the constructor, which is what I essentially propose. If that can be refined in a manageable way

@Simn
Copy link
Member

Simn commented Nov 28, 2015

I'm against this because never should mean never. If anything we should talk about #3442 (which was a bit hijacked, but the original proposal still stands).

@Simn Simn closed this as completed Nov 28, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants